From 90c4405375e611bb49a54d5289ca2e7a311ecc98 Mon Sep 17 00:00:00 2001 From: forest2001 Date: Wed, 28 Jan 2026 15:01:56 +0000 Subject: [PATCH 01/67] I hate life --- code/__DEFINES/subsystems.dm | 2 + code/controllers/failsafe.dm | 8 +- code/controllers/globals.dm | 8 +- code/controllers/master.dm | 7 +- code/controllers/subsystem/chat.dm | 61 + code/controllers/subsystem/statpanel.dm | 144 + code/modules/client/client_defines.dm | 12 + code/modules/client/verbs/ooc.dm | 2 - code/modules/goonchat/browserOutput.dm | 3 + .../browserassets/css/browserOutput.css | 848 ----- .../browserassets/js/browserOutput.js | 2782 ----------------- code/modules/tgui_panel/audio.dm | 42 + code/modules/tgui_panel/external.dm | 37 + code/modules/tgui_panel/telemetry.dm | 80 + code/modules/tgui_panel/tgui_panel.dm | 95 + vanderlin.dme | 6 +- 16 files changed, 493 insertions(+), 3644 deletions(-) create mode 100644 code/controllers/subsystem/statpanel.dm delete mode 100644 code/modules/goonchat/browserassets/css/browserOutput.css delete mode 100644 code/modules/goonchat/browserassets/js/browserOutput.js create mode 100644 code/modules/tgui_panel/audio.dm create mode 100644 code/modules/tgui_panel/external.dm create mode 100644 code/modules/tgui_panel/telemetry.dm create mode 100644 code/modules/tgui_panel/tgui_panel.dm diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index ae819da09c8..653aea7f60b 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -151,6 +151,7 @@ #define INIT_ORDER_OW -55 #define INIT_ORDER_PERSISTENCE -95 #define INIT_ORDER_BAN_CACHE -98 +#define INIT_ORDER_STATPANEL -99 #define INIT_ORDER_CHAT -100 // Should be last to ensure chat remains smooth during init. // Subsystem fire priority, from lowest to highest priority @@ -190,6 +191,7 @@ #define FIRE_PRIORITY_TGUI 110 #define FIRE_PRIORITY_TICKER 120 #define FIRE_PRIORITY_ATMOS_ADJACENCY 130 +#define FIRE_PRIORITY_STATPANEL 135 #define FIRE_PRIORITY_CHAT 140 #define FIRE_PRIORITY_RUNECHAT 150 #define FIRE_PRIORITY_MOUSE_ENTERED 160 diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index c03b94f718c..6a6d4c58d6a 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -116,8 +116,6 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) /datum/controller/failsafe/proc/defcon_pretty() return defcon -/datum/controller/failsafe/stat_entry() - if(!statclick) - statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) - - stat("Failsafe Controller:", statclick.update("Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])")) +/datum/controller/failsafe/stat_entry(msg) + msg = "Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])" + return msg diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm index 41de7dfe4c6..bd1010c8881 100644 --- a/code/controllers/globals.dm +++ b/code/controllers/globals.dm @@ -32,11 +32,9 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars) SHOULD_CALL_PARENT(FALSE) return QDEL_HINT_IWILLGC -/datum/controller/global_vars/stat_entry() - if(!statclick) - statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) - - stat("Globals:", statclick.update("Edit")) +/datum/controller/global_vars/stat_entry(msg) + msg = "Edit" + return msg /datum/controller/global_vars/vv_edit_var(var_name, var_value) if(gvars_datum_protected_varlist[var_name]) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index b744b625c35..8b1b1a4a431 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -644,13 +644,18 @@ GLOBAL_REAL(Master, /datum/controller/master) for(var/datum/controller/subsystem/ss in subsystems) //this is incase a runlevel error occurs, we don't want random shit being left queued up since if a queue ends up half parsed. ss.state = SS_IDLE - +/* /datum/controller/master/stat_entry() if(!statclick) statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))") stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])")) +*/ + +/datum/controller/master/stat_entry(msg) + msg = "(TickRate:[Master.processing]) (Iteration:[Master.iteration]) (TickLimit: [round(Master.current_ticklimit, 0.1)])" + return msg /datum/controller/master/StartLoadingMap() //disallow more than one map to load at once, multithreading it will just cause race conditions diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index e5f4985e206..4127aaffe0e 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -78,3 +78,64 @@ SUBSYSTEM_DEF(chat) return payload[C] += twiceEncoded + + +//Global chat procs +/proc/to_chat_immediate(target, message, handle_whitespace = TRUE) + if(!target || !message) + return + + if(target == world) + target = GLOB.clients + + var/original_message = message + if(handle_whitespace) + message = replacetext(message, "\n", "
") + message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") //EIGHT SPACES IN TOTAL!! + + if(islist(target)) + // Do the double-encoding outside the loop to save nanoseconds + var/twiceEncoded = url_encode(url_encode(message)) + for(var/I in target) + var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible + + if (!C) + continue + + //Send it to the old style output window. + SEND_TEXT(C, original_message) + + if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. + continue + + if(!C.chatOutput.loaded) + //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + continue + + C << output(twiceEncoded, "browseroutput:output") + else + var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible + + if (!C) + return + + //Send it to the old style output window. + SEND_TEXT(C, original_message) + + if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. + return + + if(!C.chatOutput.loaded) + //Client still loading, put their messages in a queue + C.chatOutput.messageQueue += message + return + + // url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. + C << output(url_encode(url_encode(message)), "browseroutput:output") + +/proc/to_chat(target, message, handle_whitespace = TRUE) + if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized) + to_chat_immediate(target, message, handle_whitespace) + return + SSchat.queue(target, message, handle_whitespace) diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm new file mode 100644 index 00000000000..84ac6828e44 --- /dev/null +++ b/code/controllers/subsystem/statpanel.dm @@ -0,0 +1,144 @@ +SUBSYSTEM_DEF(statpanels) + name = "Stat Panels" + wait = 4 + init_order = INIT_ORDER_STATPANEL + priority = FIRE_PRIORITY_STATPANEL + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + var/list/currentrun = list() + var/encoded_global_data + var/mc_data_encoded + var/list/cached_images = list() + +/datum/controller/subsystem/statpanels/fire(resumed = FALSE) + if (!resumed) +// var/datum/map_config/cached = SSmapping.next_map_config +// var/round_time = world.time - SSticker.round_start_time + var/list/global_data = list( + "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]", + "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]", + "Round Time: [duration2text()]", + "Map: [SSmapping.config?.map_name || "Loading..."]", + ) + + encoded_global_data = url_encode(json_encode(global_data)) + src.currentrun = GLOB.clients.Copy() + mc_data_encoded = null + var/list/currentrun = src.currentrun + while(length(currentrun)) + var/client/target = currentrun[length(currentrun)] + currentrun.len-- + if(!target.statbrowser_ready) + continue + if(target.stat_tab == "Status") +// var/ping_str = url_encode("Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)") + var/other_str = url_encode(json_encode(target.mob.get_status_tab_items())) + target << output("[encoded_global_data];null;[other_str]", "statbrowser:update") + if(!target.admin_holder) + target << output("", "statbrowser:remove_admin_tabs") + else + if(!("Admin" in target.panel_tabs)) + target << output("[url_encode(target.admin_holder.href_token)]", "statbrowser:add_admin_tabs") + if(!("MC" in target.panel_tabs) && check_client_rights(target, R_DEBUG|R_HOST, FALSE)) + target << output("", "statbrowser:add_mc_tab") + if(target.stat_tab == "MC") + var/turf/eye_turf = get_turf(target.eye) + var/coord_entry = url_encode(COORD(eye_turf)) + if(!mc_data_encoded) + generate_mc_data() + target << output("[mc_data_encoded];[coord_entry]", "statbrowser:update_mc") + if(target.mob) + var/mob/M = target.mob + if(M?.listed_turf) + var/mob/target_mob = M + if(!target_mob.TurfAdjacent(target_mob.listed_turf)) + target << output("", "statbrowser:remove_listedturf") + target_mob.listed_turf = null + else if(target.stat_tab == M?.listed_turf.name || !(M?.listed_turf.name in target.panel_tabs)) + var/list/overrides = list() + var/list/turfitems = list() + for(var/img in target.images) + var/image/target_image = img + if(!target_image.loc || target_image.loc.loc != target_mob.listed_turf || !target_image.override) + continue + overrides += target_image.loc + turfitems[++turfitems.len] = list("[target_mob.listed_turf]", REF(target_mob.listed_turf), htmlicon(target_mob.listed_turf, target, sourceonly=TRUE)) + for(var/tc in target_mob.listed_turf) + var/atom/movable/turf_content = tc + if(turf_content.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) + continue + if(turf_content.invisibility > target_mob.see_invisible) + continue + if(turf_content in overrides) + continue + //if(turf_content.IsObscured()) // requires click under flags to work + // continue + if(length(turfitems) < 30) // only create images for the first 30 items on the turf, for performance reasons + if(!(REF(turf_content) in cached_images)) + cached_images += REF(turf_content) + turf_content.RegisterSignal(turf_content, COMSIG_PARENT_QDELETING, /atom/.proc/remove_from_cache) // we reset cache if anything in it gets deleted + if(ismob(turf_content) || length(turf_content.overlays) > 2) + turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), costly_icon2html(turf_content, target, sourceonly=TRUE)) + else + turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), icon2html(turf_content, target, sourceonly=TRUE)) + else + turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content)) + else + turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content)) + turfitems = url_encode(json_encode(turfitems)) + target << output("[turfitems];", "statbrowser:update_listedturf") + if(MC_TICK_CHECK) + return + + +/datum/controller/subsystem/statpanels/proc/generate_mc_data() + var/list/mc_data = list( + list("CPU:", world.cpu), + list("Instances:", "[num2text(world.contents.len, 10)]"), + list("World Time:", "[world.time]"), + list("Globals:", GLOB.stat_entry(), "\ref[GLOB]"), + list("[config]:", config.stat_entry(), "\ref[config]"), +// list("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)"), + list("Master Controller:", Master.stat_entry(), "\ref[Master]"), + list("Failsafe Controller:", Failsafe.stat_entry(), "\ref[Failsafe]"), + list("","") + ) + for(var/ss in Master.subsystems) + var/datum/controller/subsystem/sub_system = ss + mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), "\ref[sub_system]") + //mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", "\ref[GLOB.cameranet]") + mc_data_encoded = url_encode(json_encode(mc_data)) + +/atom/proc/remove_from_cache() + SSstatpanels.cached_images -= REF(src) + +/// verbs that send information from the browser UI +/client/verb/set_tab(tab as text|null) + set name = "Set Tab" + set hidden = TRUE + + stat_tab = tab + +/client/verb/send_tabs(tabs as text|null) + set name = "Send Tabs" + set hidden = TRUE + + panel_tabs |= tabs + +/client/verb/remove_tabs(tabs as text|null) + set name = "Remove Tabs" + set hidden = TRUE + + panel_tabs -= tabs + +/client/verb/reset_tabs() + set name = "Reset Tabs" + set hidden = TRUE + + panel_tabs = list() + +/client/verb/panel_ready() + set name = "Panel Ready" + set hidden = TRUE + + statbrowser_ready = TRUE + init_verbs() diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 82f018f029a..0b8a8abacce 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -148,3 +148,15 @@ var/list/real_like_cooldowns = list() /// Total Real likes received in a round - For Mentor var/real_likes_received = 0 + + /// our current tab + var/stat_tab + + /// whether our browser is ready or not yet + var/statbrowser_ready = FALSE + + /// list of all tabs + var/list/panel_tabs = list() + + ///A lazy list of atoms we've examined in the last EXAMINE_MORE_TIME (default 1.5) seconds, so that we will call [/atom/proc/examine_more] instead of [/atom/proc/examine] on them when examining + var/list/recent_examines diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index c3b75bd61fb..d11e5f743d6 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -360,12 +360,10 @@ GLOBAL_LIST_INIT(oocpronouns_required, list( return else - chatOutput.start() var/action = alert(src, "Manually loading Chat, wait a bit and tell me if it's fixed", "", "Fixed", "Nope") if (action == "Fixed") log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by manually calling start()") else - chatOutput.load() alert(src, "How about now? (give it a moment (it may also try to load twice))", "", "Yes", "No") if (action == "Yes") log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by manually calling start() and forcing a load()") diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 6746e15f0ab..37d5d85877c 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -1,3 +1,4 @@ +/* #define MAX_COOKIE_LENGTH 5 /********************************* @@ -297,3 +298,5 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico owner.force_dark_theme() #undef MAX_COOKIE_LENGTH + +*/ diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css deleted file mode 100644 index a4185cee9a8..00000000000 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ /dev/null @@ -1,848 +0,0 @@ -/***************************************** -* -* GLOBAL STYLES -* -******************************************/ -html, body { - padding: 0; - margin: 0; - height: 100%; - color: #c9c1ba; -} -body { - background: #000000; - font-family: Pterra; - font-size: 13px; - color: #c9c1ba; - line-height: 1.2; - overflow-x: hidden; - overflow-y: scroll; - word-wrap: break-word; - scrollbar-face-color:#1A1A1A; - scrollbar-track-color:#171717; - scrollbar-highlight-color:#171717; - text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000; -} - - -/* Fonts */ -@font-face { - font-family: "Pterra"; - src: url('pterra.ttf') format('truetype'); -} -@font-face { - font-family: "Honoka Mincho"; - src: url('HonokaMincho.ttf') format('truetype'); -} - -@font-face { - font-family: "Dauphin"; - src: url('elf.ttf') format('truetype'); -} - -@font-face { - font-family: "MasonAlternate"; - src: url('dwarf.ttf') format('truetype'); -} - -@font-face { - font-family: "Arabolical"; - src: url('sand.ttf') format('truetype'); -} - -@font-face { - font-family: "Xaphan"; - src: url('hell.ttf') format('truetype'); -} - -@font-face { - font-family: "FriskyVampire"; - src: url('undead.ttf') format('truetype'); -} - -@font-face { - font-family: "Thief by The Riddler"; - src: url('orc.ttf') format('truetype'); -} - -@font-face { - font-family: "Notredame"; - src: url('otavan.ttf'); -} - -@font-face { - font-family: "Underwater Love"; - src: url('deepspeak.ttf') format('truetype'); -} - -@font-face { - font-family: "Kingthings Petrock"; - src: url('draconic.ttf') format('truetype'); -} - -@font-face { - font-family: "Emperialisme"; - src: url('lupian.ttf') format('truetype'); -} - -/* */ - -em { - font-style: normal; - font-weight: bold; -} - -img { - margin: 0; - padding: 0; - line-height: 1; - -ms-interpolation-mode: nearest-neighbor; - image-rendering: pixelated; -} -img.icon { - height: 1em; - min-height: 16px; - width: auto; - vertical-align: bottom; -} - -.r:before { /* "repeated" badge class for combined messages */ - content: 'x'; -} -.r { - display: inline-block; - min-width: 0.5em; - font-size: 0.7em; - padding: 0.2em 0.3em; - line-height: 1.2; - color: white; - text-align: center; - white-space: nowrap; - vertical-align: middle; - background-color: crimson; - border-radius: 10px; -} - -a {color: #397ea5;} -a.visited {color: #7c00e6;} -a:visited {color: #7c00e6;} -a.popt {text-decoration: none;} - -.chat_box { - display: inline-block; - width: calc(100% - 1em); - margin: 0.5em; - padding: 0.5em 0.75em; - box-sizing: border-box; -} - -.examine_block { - background: #0f0f0f; - border: 1px solid #1d1d1f; -} - -.mentor_block { - background: #3e263a; - border: 1px dotted #7f4274; -} - -.announcement_block { - background: #2c032f; - border: 6px inset #990b3f; -} - -/***************************************** -* -* OUTPUT NOT RELATED TO ACTUAL MESSAGES -* -******************************************/ -#loading { - position: fixed; - width: 300px; - height: 150px; - text-align: center; - left: 50%; - top: 50%; - margin: -75px 0 0 -150px; -} -#loading i {display: block; padding-bottom: 3px;} - -#filterTabs { - position: fixed; - top: 0; - left: 0; - right: 0; - background: #2d2d2d; - border-bottom: 2px solid #4CAF50; - z-index: 100; - display: flex; - flex-wrap: wrap; - padding: 5px; - box-shadow: 0 2px 5px rgba(0,0,0,0.3); -} - -.filter-tab { - background: #3d3d3d; - color: #ffffff; - border: 1px solid #000000; - padding: 8px 15px; - margin: 2px; - cursor: pointer; - border-radius: 4px; - transition: all 0.3s ease; - font-size: 12px; - position: relative; - user-select: none; -} - -.filter-tab:hover { - background: #4d4d4d; - transform: translateY(-1px); -} - -.filter-tab.active { - background: #1b1b1b; - font-weight: bold; -} - -.filter-tab.custom { - background: #413e3c; -} - -.filter-tab.custom.active { - background: #555251; -} - -.filter-tab .remove-tab { - margin-left: 8px; - color: #ff4444; - font-weight: bold; - cursor: pointer; -} - -.filter-tab .remove-tab:hover { - color: #ff0000; -} - -#addTabBtn { - background: #6c757d; - color: white; - border: none; - padding: 8px 12px; - margin: 2px; - border-radius: 4px; - cursor: pointer; - font-size: 12px; - transition: background 0.3s ease; -} - -#addTabBtn:hover { - background: #5a6268; -} - -#addTabForm { - display: none; - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background: #2d2d2d; - border: 1px solid #555; - border-radius: 8px; - padding: 20px; - z-index: 1000; - min-width: 300px; -} - -#addTabForm input { - width: 100%; - padding: 8px; - margin: 5px 0; - background: #3d3d3d; - border: 1px solid #555; - border-radius: 4px; - color: #ffffff; -} - -#addTabForm button { - padding: 8px 15px; - margin: 5px; - border: none; - border-radius: 4px; - cursor: pointer; -} - -#addTabForm .save { - background: #4CAF50; - color: white; -} - -#addTabForm .cancel { - background: #6c757d; - color: white; -} - -.hidden { - display: none !important; -} - -/* Responsive design */ -@media (max-width: 768px) { - #filterTabs { - font-size: 11px; - } - - .filter-tab { - padding: 6px 10px; - font-size: 11px; - } - - #userBar { - flex-direction: column; - gap: 5px; - } -} -#messages { - font-size: 13px; - padding: 3px; - margin: 0; - word-wrap: break-word; - padding-top: 60px; -} -#newMessages { - position: fixed; - display: block; - bottom: 0; - right: 0; - padding: 8px; - background: #202020; - text-decoration: none; - font-variant: small-caps; - font-size: 1.1em; - font-weight: bold; - color: #c9c1ba; -} -#newMessages:hover {background: #000000;} -#newMessages i {vertical-align: middle; padding-left: 3px;} -#ping { - padding: 8px 0 2px 0; -} -#ping i {display: block; text-align: center;} -#ping .ms { - display: block; - text-align: center; - font-size: 8pt; - padding-top: 2px; -} -#userBar { - position: fixed; - top: 0; - right: 0; - padding-top: 60px; -} -#userBar .subCell { - background: #202020; - height: 30px; - padding: 5px 0; - display: block; - color: #EEEEEE; - text-decoration: none; - line-height: 28px; - border-top: 1px solid #171717; -} -#userBar .subCell:hover {background: #202020;} -#userBar .toggle { - width: 45px; - background: #202020; - border-top: 0; - float: right; - text-align: center; -} -#userBar .sub {clear: both; display: none; width: 200px;} -#userBar .sub.scroll {overflow-y: scroll;} -#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} -#userBar .sub span { - display: block; - line-height: 30px; - float: left; -} -#userBar .sub i { - display: block; - padding: 0 5px; - font-size: 1.1em; - width: 22px; - text-align: center; - line-height: 30px; - float: right; -} -#userBar .sub input { - position: absolute; - padding: 7px 5px; - width: 121px; - line-height: 30px; - float: left; -} -#userBar .topCell {border-top: 0;} - -/* WebSocket Standalone Popup - Centers on screen like filters */ -#subWebsocket { - position: fixed !important; - top: 50% !important; - left: 50% !important; - transform: translate(-50%, -50%) !important; - z-index: 9999 !important; - width: 320px !important; - background: #2a2a2a !important; - border: 1px solid #555 !important; - border-radius: 8px !important; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6) !important; -} - -/* Backdrop overlay */ -#subWebsocket::before { - content: '' !important; - position: fixed !important; - top: 0 !important; - left: 0 !important; - width: 100vw !important; - height: 100vh !important; - background: rgba(0, 0, 0, 0.5) !important; - z-index: -1 !important; -} - -#subWebsocket .websocket-settings { - position: relative !important; - padding: 20px !important; - background: #2a2a2a !important; - border-radius: 8px !important; - width: 100% !important; - height: 220px !important; - box-sizing: border-box !important; -} - -/* Status */ -#websocketStatus { - position: absolute !important; - top: 20px !important; - left: 20px !important; - right: 20px !important; - height: 30px !important; - padding: 6px 12px !important; - border-radius: 4px !important; - font-weight: bold !important; - text-align: center !important; - font-size: 13px !important; - line-height: 18px !important; -} - -#websocketStatus.connected { background: #4CAF50 !important; color: white !important; } -#websocketStatus.disconnected { background: #f44336 !important; color: white !important; } -#websocketStatus.connecting { background: #ff9800 !important; color: white !important; } - -/* Checkbox Row */ -.websocket-checkbox-row { - position: absolute !important; - top: 70px !important; - left: 20px !important; - right: 20px !important; - height: 25px !important; - display: flex !important; - align-items: center !important; - color: #fff !important; - font-size: 14px !important; - cursor: pointer !important; -} - -.websocket-checkbox-row input[type="checkbox"] { - margin: 0 10px 0 0 !important; - transform: scale(1.2) !important; -} - -/* Server Input Group */ -.websocket-server-group { - position: absolute !important; - top: 110px !important; - left: 20px !important; - right: 20px !important; - height: 60px !important; -} - -.websocket-server-group label { - position: absolute !important; - top: 0 !important; - left: 0 !important; - color: #fff !important; - font-size: 14px !important; - line-height: 20px !important; -} - -#websocketServer { - position: static !important; - display: block !important; - width: 100% !important; - height: 36px !important; - padding: 10px 12px !important; - margin: 8px 0 16px 0 !important; - border: 1px solid #555 !important; - background: #333 !important; - color: #fff !important; - border-radius: 4px !important; - box-sizing: border-box !important; - font-size: 14px !important; - float: none !important; - clear: both !important; -} - -.websocket-server-group input:focus { - outline: none !important; - border-color: #007cba !important; - box-shadow: 0 0 0 2px rgba(0, 124, 186, 0.3) !important; -} - -/* Button Controls */ -.websocket-controls { - position: absolute !important; - bottom: 20px !important; - left: 20px !important; - right: 20px !important; - height: 36px !important; - display: flex !important; - gap: 8px !important; -} - -.websocket-controls button { - flex: 1 !important; - height: 36px !important; - padding: 0 !important; - border: none !important; - border-radius: 4px !important; - cursor: pointer !important; - background: #555 !important; - color: white !important; - font-size: 12px !important; - font-weight: 500 !important; - transition: background-color 0.2s ease !important; - text-align: center !important; -} - -.websocket-controls button:hover { - background: #666 !important; -} - -#connectWebsocket { - background: #007cba !important; -} - -#connectWebsocket:hover { - background: #0056b3 !important; -} - -.websocket-controls button:disabled { - opacity: 0.5 !important; - cursor: not-allowed !important; -} - -/* Close button (add this to your HTML if needed) */ -.websocket-close { - position: absolute !important; - top: 8px !important; - right: 8px !important; - width: 24px !important; - height: 24px !important; - background: none !important; - border: none !important; - color: #aaa !important; - cursor: pointer !important; - font-size: 18px !important; - line-height: 1 !important; -} - -.websocket-close:hover { - color: #fff !important; -} -/* POPUPS */ -.popup { - position: fixed; - top: 50%; - left: 50%; - background: #ddd; -} -.popup .close { - position: absolute; - background: #aaa; - top: 0; - right: 0; - color: #333; - text-decoration: none; - z-index: 2; - padding: 0 10px; - height: 30px; - line-height: 30px; -} -.popup .close:hover {background: #999;} -.popup .head { - background: #999; - color: #ddd; - padding: 0 10px; - height: 30px; - line-height: 30px; - text-transform: uppercase; - font-size: 0.9em; - font-weight: bold; - border-bottom: 2px solid green; -} -.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} -.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} -.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} -.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} - -.changeFont {padding: 10px;} -.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} -.changeFont a:hover {background: #ccc;} - -.highlightPopup {padding: 10px; text-align: center;} -.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} -.highlightPopup input.highlightColor {background-color: #FFFF00;} -.highlightPopup input.highlightTermSubmit {margin-top: 5px;} - -/* ADMIN FILTER MESSAGES MENU */ -.filterMessages {padding: 5px;} -.filterMessages div {padding: 2px 0;} -.filterMessages input {} -.filterMessages label {} - -.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} - - -/***************************************** -* -* OUTPUT ACTUALLY RELATED TO MESSAGES -* -******************************************/ - -body {word-wrap: break-word; overflow-x: hidden; overflow-y: scroll; color: #c9c1ba; font-size: 16px; font-family: "Pterra";} - -h1, h2, h3, h4, h5, h6 {color: #c9c1ba; font-family: Pterra;} - -em {font-style: normal; font-weight: bold; font-family: Pterra;} - -a:link {color: #ae83cb; font-weight: bold;} - -.motd {color: #638500; font-family: Pterra;} -.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 - {color: #638500; text-decoration: underline;} -.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover - {color: #638500;} -h1.alert, h2.alert {color: #c9c1ba;font-family: Pterra, TrueType;} -.italics {font-style: italic;} - -.bold {font-weight: bold;} - -.prefix {font-weight: bold;} - -.ooc {color: #c5c5c5; font-weight: bold; font-family: Pterra;} -.adminobserverooc {color: #cca300; font-weight: bold; font-family: Pterra;} -.adminooc {color: #4972bc; font-weight: bold;} - -.adminsay {color: #FF4500; font-weight: bold;} -.admin {color: #386aff; font-weight: bold;} - -.name { font-weight: bold;} - -.say {font-family: Pterra;} -.deadsay {color: #e2c1ff;} -.binarysay {color: #20c20e; background-color: #000000; display: block;} -.binarysay a {color: #00ff00;} -.binarysay a:active, .binarysay a:visited {color: #88ff88;} -.radio {color: #1ecc43;} - - -.yell {font-weight: bold;} - -.alert {color: #d82020;} - -.alert_holder{ - border: 0.1rem solid #FFF; - border-radius: 0.6rem; - padding: 1rem; -} - -.emote {color: #b1bb9f; font-size: 75%;} - -.crit {color: #c71d76;} -.userdanger {color: #c71d76; font-weight: bold; font-size: 120%;} -.danger {color: #b9322b; font-weight: bold;} -.warning {color: #bb4e28; font-size: 75%;} -.warningbig {color: #bb4e28;} -.boldwarning {color: #bb4e28; font-weight: bold} -.announce {color: #c51e1e; font-weight: bold;} -.boldannounce {color: #c51e1e; font-weight: bold;} -.greenannounce {color: #059223; font-weight: bold;} -.rose {color: #e7bed8;} -.love {color: #e7bed8; font-size: 75%;} -.info {color: #a9a5b6; font-size: 75%; line-height:1} -.biginfo {color: #a9a5b6;} -.notice {color: #f1d669;} -.boldnotice {color: #f1d669; font-weight: bold;} -.smallnotice {color: #f1d669; font-size: 75%;} -.hear {color: #6685f5; font-style: italic;} -.adminnotice {color: #6685f5;} -.adminannouncebig {color: #6685f5; font-style: bold; font-size: 200%} -.adminannounce {color: #6685f5; font-style: bold; font-size: 120%} -.adminhelp {color: #ff0000; font-weight: bold;} -.unconscious {color: #c9c1ba; font-weight: bold;} -.suicide {color: #ff5050; font-style: italic;} -.green {color: #80b077;} -.good {color: #00ff00;} -.smallgreen {color: #80b077; font-size: 75%;} -.boldgreen {color: #80b077; font-weight: bold;} -.red {color: #b84d47;} -.smallred {color: #b84d47; font-size: 75%;} -.boldred {color: #b84d47; font-weight: bold;} -.blue {color: #6a8cb7;} -.lightpurple {color: #967aaf;} -.nicegreen {color: #9bccd0;} -.cult {color: #960000;} -.cultsmall {color: #960000; font-size: 75%;} -.narsie {color: #960000; font-weight: bold; font-size: 12;} -.narsiesmall {color: #960000; font-weight: bold; font-size: 6;} -.colossus {color: #7F282A; font-size: 5;} -.hierophant {color: #660099; font-weight: bold; font-style: italic;} -.hierophant_warning {color: #660099; font-style: italic;} -.purple {color: #5e2d79;} -.beautifulmasc {color: #083eab;} -.beautifulfem {color: #d70a74;} -.beautifulnb {color: #9656c9;} - -.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;} - -.alien {color: #543354;} -.noticealien {color: #00c000;} -.alertalien {color: #00c000; font-weight: bold;} - -.interface {color: #DA00DA;} - -.sans {font-family: "Comic Sans MS", cursive, sans-serif;} -.papyrus {font-family: "Papyrus", cursive, sans-serif;} - -.human {font-family: "Honoka Mincho", "Pterra";} -.elf {font-family: "Dauphin", cursive, "Pterra";} -.dwarf {font-family: "MasonAlternate", "Pterra";} -.sandspeak {font-family: "Arabolical", "Pterra";} -.delf {font-family: "Dauphin", "Pterra";} -.hellspeak {font-family: "Xaphan", "Pterra"; font-size: 110%} -.undead {font-family: "FriskyVampire", "Pterra";} -.orc {font-family: "Thief by The Riddler", Pterra;} -.otavan {font-family: "Notredame", Pterra; font-size: 200%;} -.beast {font-family: "Thief by The Riddler", Pterra;} -.reptile {font-family: "Kingthings Petrock", Pterra; font-size: 120%;} -.deepspeak {font-family: "Underwater Love", Pterra;} -.lupian {font-family: "Emperialisme", Pterra; font-size: 120%;} - -.torture {color: #42ff20} - -.command_headset {font-weight: bold; font-size: 3;} -.small {font-size: 50%;} -.smallyell {font-size: 70%;font-family: Pterra;} -.big {font-size: 120%;} -.reallybig {font-size: 180%;} -.extremelybig {font-size: 220%;} -.greentext {color: #00FF00;} -.redtext {color: #FF0000;} -.clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} -.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} -.hypnophrase {color: #3bb5d3; font-weight: bold; animation: hypnocolor 1500ms infinite;} - -.phobia {color: #dd0000; font-weight: bold;} - -.icon {height: 1em; width: auto;} - -.memo {color: #638500; text-align: center;} -.memoedit {text-align: center; font-size: 2;} -.abductor {color: #800080; font-style: italic;} -.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} -.drone {color: #848482;} - -.dead {color: #b280df;} -.bloody {color: #cc0f0f;} -.artery {color: #9B5455;} -.infection {color: #77c72b;} -.necrosis {color: #558d20;} -.bone {color: #e3dac9;} -.love_low {color: #eac8de; font-size: 75%;} -.love_mid {color: #e9a8d1; font-size: 75%;} -.love_high {color: #f05ee1; font-size: 75%;} -.love_extreme {color: #d146f5; font-size: 75%;} - -.silver {color: #c0c0c0;} - -/* -@keyframes hypnocolor { - 0% {color: #202020;} - 25% {color: #4b02ac;} - 50% {color: #9f41f1;} - 75% {color: #541c9c;} - 100% {color: #7adbf3;} -} - -.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} -@keyframes phobia { - 0% {color: #f75a5a;} - 50% {color: #dd0000;} - 100% {color: #f75a5a;} -} -*/ - -.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} -.connectionClosed.restored {background: green;} -.internal.boldnshit {color: #3d5bc3; font-weight: bold;} - -/* HELPER CLASSES */ -.text-normal {font-weight: normal; font-style: normal;} -.hidden {display: none; visibility: hidden;} - -/* Tooltips */ -.tooltip-trigger { - position: relative; - cursor: help; - text-decoration: underline dotted; -} -/* Alt Tooltip (No Italics) */ -.tooltip-alt-trigger { - font-style: normal; -} - -.tooltip-trigger::after, -.tooltip-trigger::before { - content: ''; - position: absolute; - visibility: hidden; - opacity: 0; - transition: opacity 0.3s, visibility 0.3s; - pointer-events: none; -} - -/* Tooltip content */ -.tooltip-trigger::after { - content: attr(data-tooltip); - background-color: rgba(0, 0, 0, 0.85); - color: #fff; - text-align: center; - border-radius: 5px; - padding: 8px 12px; - font-size: 0.9em; - white-space: nowrap; - z-index: 1000; - - bottom: 120%; - left: 50%; - transform: translateX(-50%); -} - -/* Show tooltip on hover */ -.tooltip-trigger:hover::after, -.tooltip-trigger:hover::before { - visibility: visible; - opacity: 1; -} - diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js deleted file mode 100644 index 92b675c6790..00000000000 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ /dev/null @@ -1,2782 +0,0 @@ - -/***************************************** -* -* FUNCTION AND VAR DECLARATIONS -* -******************************************/ - -//DEBUG STUFF -var escaper = encodeURIComponent || escape; -var decoder = decodeURIComponent || unescape; -window.onerror = function(msg, url, line, col, error) { - if (document.location.href.indexOf("proc=debug") <= 0) { - var extra = !col ? '' : ' | column: ' + col; - extra += !error ? '' : ' | error: ' + error; - extra += !navigator.userAgent ? '' : ' | user agent: ' + navigator.userAgent; - var debugLine = 'Error: ' + msg + ' | url: ' + url + ' | line: ' + line + extra; - window.location = '?_src_=chat&proc=debug¶m[error]='+escaper(debugLine); - } - return true; -}; - -//Globals -var messageQueue = { - messages: [], - processing: false, - batchSize: 10, // Process this many at once - batchDelay: 16, // ~60fps - - add: function(message, flag) { - this.messages.push({message: message, flag: flag}); - if (!this.processing) { - this.processing = true; - requestAnimationFrame(() => this.processBatch()); - } - }, - - processBatch: function() { - if (this.messages.length === 0) { - this.processing = false; - return; - } - - // Process up to batchSize messages - var batch = this.messages.splice(0, this.batchSize); - var fragment = document.createDocumentFragment(); - var atBottom = this.checkIfAtBottom(); - - // Process all messages in batch - batch.forEach(item => { - var entry = this.createMessageElement(item.message, item.flag); - if (entry) { - fragment.appendChild(entry); - } - }); - - // Apply highlights BEFORE appending to DOM (more efficient) - if (window.highlightSystem && highlightSystem.filters && highlightSystem.filters.length > 0) { - this.batchHighlight(fragment); - } - - // Apply linkify and other processing - var entries = Array.prototype.slice.call(fragment.children); - entries.forEach(function(entry) { - // Linkify - var to_linkify = entry.querySelectorAll ? entry.querySelectorAll('.linkify') : []; - if (typeof Node === 'undefined') { - for(var i = 0; i < to_linkify.length; ++i) { - to_linkify[i].innerHTML = linkify_fallback(to_linkify[i].innerHTML); - } - } else { - for(var i = 0; i < to_linkify.length; ++i) { - linkify_node(to_linkify[i]); - } - } - - // Icon error handlers - var icons = entry.querySelectorAll ? entry.querySelectorAll('img.icon') : []; - for(var i = 0; i < icons.length; i++) { - icons[i].addEventListener('error', iconError); - } - - // Replace regex - var replaceElements = entry.querySelectorAll ? entry.querySelectorAll('[replaceRegex]') : []; - for(var i = 0; i < replaceElements.length; i++) { - var selectedRegex = replaceRegexes[replaceElements[i].getAttribute('replaceRegex')]; - if (selectedRegex) { - var replacedText = replaceElements[i].innerHTML.replace(selectedRegex[0], selectedRegex[1]); - replaceElements[i].innerHTML = replacedText; - } - replaceElements[i].removeAttribute('replaceRegex'); - } - }); - - // Single DOM append for entire batch - $messages[0].appendChild(fragment); - - // Cleanup old messages in one go - this.cleanupOldMessages(); - - // Handle scroll once - if (atBottom) { - this.scrollToBottom(); - } - - // Continue processing if more messages - if (this.messages.length > 0) { - setTimeout(() => requestAnimationFrame(() => this.processBatch()), this.batchDelay); - } else { - this.processing = false; - } - }, - - checkIfAtBottom: function() { - var bodyHeight = window.innerHeight; - var messagesHeight = $messages[0].scrollHeight; - var scrollPos = window.pageYOffset || document.documentElement.scrollTop; - return bodyHeight + scrollPos >= messagesHeight - opts.scrollSnapTolerance; - }, - - scrollToBottom: function() { - // Use RAF for smooth scroll - requestAnimationFrame(() => { - $('body,html').scrollTop($messages.outerHeight()); - }); - }, - - createMessageElement: function(message, flag) { - if (typeof message === 'undefined') return null; - - message = byondDecode(message).trim(); - - var entry = document.createElement('div'); - entry.innerHTML = message; - entry.className = 'entry'; - - opts.messageCount++; - - // Apply filter efficiently - this.quickFilterCheck(entry); - - return entry; - }, - - quickFilterCheck: function(entry) { - // Fast path for 'all' filter - if (opts.currentFilter === 'all') return; - - // Cache class list as string for faster searching - var classStr = ' ' + entry.className + ' '; - var innerHTML = entry.innerHTML; - - var shouldShow = classStr.indexOf(' ' + opts.currentFilter + ' ') !== -1 || - innerHTML.indexOf('class="' + opts.currentFilter) !== -1; - - // Check custom tabs (optimized) - if (!shouldShow && opts.customTabs && opts.customTabs.length > 0) { - for (var i = 0; i < opts.customTabs.length; i++) { - var tab = opts.customTabs[i]; - if (tab.name.toLowerCase() === opts.currentFilter) { - for (var j = 0; j < tab.classes.length; j++) { - if (classStr.indexOf(' ' + tab.classes[j] + ' ') !== -1 || - innerHTML.indexOf('class="' + tab.classes[j]) !== -1) { - shouldShow = true; - break; - } - } - break; - } - } - } - - if (!shouldShow) { - entry.classList.add('filtered-hidden'); - entry.style.display = 'none'; - } - }, - - cleanupOldMessages: function() { - while (opts.messageCount > opts.messageLimit) { - var first = $messages[0].firstElementChild; - if (first) { - first.remove(); - opts.messageCount--; - } else { - break; - } - } - }, - - batchHighlight: function(fragment) { - // Only highlight if filters are enabled - if (!highlightSystem || !highlightSystem.filters) return; - - var enabledFilters = highlightSystem.filters.filter(f => f.enabled && f.term.trim()); - if (enabledFilters.length === 0) return; - - // Get entries - fragment is not yet in DOM so we need to iterate its children - var entries; - if (fragment.children) { - entries = Array.prototype.slice.call(fragment.children); - } else if (fragment.childNodes) { - entries = Array.prototype.filter.call(fragment.childNodes, function(node) { - return node.nodeType === 1; // Element nodes only - }); - } else { - return; - } - - // Apply highlights to each entry - entries.forEach(function(entry) { - if (entry && entry.nodeType === 1) { - highlightSystem.highlightElement(entry); - } - }); - } -}; - -var highlightSystem = { - filters: [], // Array of {term: string, color: string, animation: string, enabled: boolean, id: string, soundEnabled: boolean} - animations: { - 'none': 'No animation', - 'glow': 'Glow effect', - 'pulse': 'Pulse animation', - 'flash': 'Flash animation', - 'rainbow': 'Rainbow effect', - }, - - // Initialize the system - init: function() { - this.loadFilters(); - this.injectStyles(); - }, - - // Inject required CSS styles - injectStyles: function() { - if (document.getElementById('highlightSystemStyles')) return; - - var style = document.createElement('style'); - style.id = 'highlightSystemStyles'; - style.textContent = ` - /* Fixed animations */ - @keyframes glow { - 0%, 100% { - box-shadow: 0 0 5px currentColor; - filter: brightness(1); - } - 50% { - box-shadow: 0 0 20px currentColor, 0 0 30px currentColor; - filter: brightness(1.3); - } - } - .highlight-glow { - animation: glow 2s infinite; - border-radius: 3px; - } - - @keyframes pulse { - 0%, 100% { - transform: scale(1); - opacity: 1; - } - 50% { - transform: scale(1.1); - opacity: 0.7; - } - } - .highlight-pulse { - animation: pulse 1.5s infinite; - display: inline-block; - border-radius: 3px; - } - - @keyframes flash { - 0%, 50%, 100% { opacity: 1; } - 25%, 75% { opacity: 0.3; } - } - .highlight-flash { - animation: flash 1s infinite; - border-radius: 3px; - } - - @keyframes bounce { - 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } - 40% { transform: translateY(-3px); } - 60% { transform: translateY(-2px); } - } - .highlight-bounce { - animation: bounce 2s infinite; - display: inline-block; - border-radius: 3px; - } - - @keyframes slide { - 0% { background-position: -200% 0; } - 100% { background-position: 200% 0; } - } - .highlight-slide { - background: linear-gradient(90deg, transparent 30%, var(--highlight-color, #FFFF00) 50%, transparent 70%); - background-size: 200% 100%; - animation: slide 2s infinite; - border-radius: 3px; - } - - @keyframes rainbow { - 0% { background-color: #ff0000; color: white; } - 14% { background-color: #ff8000; color: white; } - 28% { background-color: #ffff00; color: black; } - 42% { background-color: #80ff00; color: black; } - 57% { background-color: #00ff80; color: black; } - 71% { background-color: #0080ff; color: white; } - 85% { background-color: #8000ff; color: white; } - 100% { background-color: #ff0000; color: white; } - } - .highlight-rainbow { - animation: rainbow 3s infinite; - font-weight: bold; - border-radius: 3px; - padding: 1px 2px; - } - - /* Darkened popup styles */ - .popup { - position: fixed; - background: linear-gradient(135deg, #0f1419 0%, #1a1d23 100%); - border: 2px solid #000000; - border-radius: 12px; - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.8); - z-index: 10000; - width: 95vw; - max-width: 600px; - max-height: 85vh; - color: #c9d1d9; - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - display: flex; - flex-direction: column; - /* Smart positioning - will be set by JavaScript */ - } - - .popup .head { - background: linear-gradient(135deg, #161b22, #21262d); - padding: 15px 20px; - border-radius: 10px 10px 0 0; - font-size: 18px; - font-weight: bold; - text-align: center; - position: relative; - flex-shrink: 0; - } - - .popup .close { - position: absolute; - top: 10px; - right: 15px; - font-size: 24px; - text-decoration: none; - color: #c9d1d9; - opacity: 0.7; - transition: opacity 0.3s ease; - width: 30px; - height: 30px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; - background: rgba(255,255,255,0.05); - } - - .popup .close:hover { - opacity: 1; - background: rgba(255,255,255,0.1); - } - - .highlight-manager { - padding: 15px; - flex: 1; - overflow: hidden; - display: flex; - flex-direction: column; - } - - #highlightFilters { - flex: 1; - overflow-y: auto; - margin-bottom: 15px; - padding-right: 8px; - max-height: 400px; - } - - /* Custom scrollbar - darker */ - #highlightFilters::-webkit-scrollbar { - width: 6px; - } - - #highlightFilters::-webkit-scrollbar-track { - background: rgba(0, 0, 0, 0.3); - border-radius: 3px; - } - - #highlightFilters::-webkit-scrollbar-thumb { - background: rgba(100, 100, 100, 0.4); - border-radius: 3px; - } - - #highlightFilters::-webkit-scrollbar-thumb:hover { - background: rgba(120, 120, 120, 0.6); - } - - .highlight-filter-item { - background: rgba(0, 0, 0, 0.3); - border: 1px solid rgba(100, 100, 100, 0.2); - border-radius: 8px; - padding: 12px; - margin-bottom: 12px; - transition: all 0.3s ease; - } - - .highlight-filter-item:hover { - background: rgba(0, 0, 0, 0.4); - border-color: rgba(120, 120, 120, 0.3); - } - - /* Main row for term input and color */ - .filter-main-row { - display: flex; - gap: 8px; - margin-bottom: 8px; - align-items: center; - } - - .filter-term-input { - flex: 1; - min-width: 0; - } - - .filter-color-input { - flex-shrink: 0; - } - - /* Controls row for animation, toggles, and remove */ - .filter-controls-row { - display: flex; - gap: 6px; - flex-wrap: wrap; - align-items: center; - } - - .filter-animation-select { - flex: 1; - min-width: 100px; - } - - .filter-buttons { - display: flex; - gap: 4px; - flex-shrink: 0; - } - - .highlight-filter-item input[type="text"] { - background: rgba(0, 0, 0, 0.6); - border: 1px solid rgba(80, 80, 80, 0.4); - border-radius: 4px; - padding: 6px 8px; - font-size: 13px; - color: #c9d1d9; - transition: border-color 0.3s ease; - width: 100%; - box-sizing: border-box; - } - - .highlight-filter-item input[type="text"]:focus { - outline: none; - border-color: rgba(120, 120, 120, 0.6); - box-shadow: 0 0 3px rgba(80, 80, 80, 0.5); - } - - .highlight-filter-item input[type="color"] { - width: 40px; - height: 32px; - border: 2px solid rgba(80, 80, 80, 0.4); - border-radius: 4px; - cursor: pointer; - background: rgba(0, 0, 0, 0.5); - transition: border-color 0.3s ease; - } - - .highlight-filter-item input[type="color"]:hover { - border-color: rgba(120, 120, 120, 0.6); - } - - .highlight-filter-item select { - background: rgba(0, 0, 0, 0.6); - border: 1px solid rgba(80, 80, 80, 0.4); - border-radius: 4px; - padding: 6px; - font-size: 12px; - color: #c9d1d9; - cursor: pointer; - transition: border-color 0.3s ease; - } - - .highlight-filter-item select:focus { - outline: none; - border-color: rgba(120, 120, 120, 0.6); - } - - .highlight-filter-item button { - background: rgba(30, 90, 130, 0.3); - border: 1px solid rgba(30, 90, 130, 0.5); - border-radius: 4px; - padding: 4px 8px; - color: #c9d1d9; - cursor: pointer; - font-size: 10px; - font-weight: bold; - transition: all 0.3s ease; - white-space: nowrap; - min-width: 35px; - } - - .highlight-filter-item button:hover { - background: rgba(30, 90, 130, 0.4); - transform: translateY(-1px); - } - - .toggle-btn.enabled { - background: rgba(25, 130, 70, 0.4) !important; - border-color: rgba(25, 130, 70, 0.7) !important; - color: #40d47e !important; - } - - .remove-btn:hover { - background: rgba(150, 40, 30, 0.4) !important; - border-color: rgba(150, 40, 30, 0.7) !important; - color: #ff6b6b !important; - } - - .sound-btn.enabled { - background: rgba(160, 120, 10, 0.4) !important; - border-color: rgba(160, 120, 10, 0.7) !important; - color: #ffd93d !important; - } - - .highlight-controls { - display: flex; - gap: 8px; - flex-wrap: wrap; - justify-content: center; - padding-top: 12px; - border-top: 1px solid rgba(80, 80, 80, 0.3); - flex-shrink: 0; - } - - .add-filter-btn { - background: rgba(25, 130, 70, 0.3); - border: 1px solid rgba(25, 130, 70, 0.5); - border-radius: 6px; - padding: 8px 12px; - color: #c9d1d9; - cursor: pointer; - font-size: 12px; - font-weight: bold; - transition: all 0.3s ease; - white-space: nowrap; - } - - .add-filter-btn:hover { - background: rgba(25, 130, 70, 0.4); - transform: translateY(-1px); - box-shadow: 0 3px 8px rgba(25, 130, 70, 0.4); - } - - .no-filters-message { - text-align: center; - padding: 30px 15px; - color: rgba(201, 209, 217, 0.4); - font-style: italic; - } - - /* Mobile-specific styles */ - @media (max-width: 600px) { - .popup { - width: 98vw; - max-height: 95vh; - margin: 0; - } - - .popup .head { - font-size: 16px; - padding: 12px 15px; - } - - .highlight-manager { - padding: 10px; - } - - .filter-controls-row { - flex-direction: column; - align-items: stretch; - } - - .filter-buttons { - justify-content: space-between; - margin-top: 6px; - } - - .highlight-filter-item button { - flex: 1; - padding: 8px 4px; - font-size: 9px; - } - - .highlight-controls { - flex-direction: column; - gap: 6px; - } - - .add-filter-btn { - font-size: 11px; - padding: 10px; - } - } - - /* Very small screens */ - @media (max-width: 400px) { - .filter-main-row { - flex-direction: column; - align-items: stretch; - } - - .filter-color-input { - align-self: center; - } - - .highlight-filter-item input[type="color"] { - width: 60px; - height: 35px; - } - } - `; - document.head.appendChild(style); - }, - - // Generate unique ID for filters - generateId: function() { - return 'highlight_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); - }, - - // Add a new highlight filter - addFilter: function(term, color = '#FFFF00', animation = 'none') { - var filter = { - id: this.generateId(), - term: term.toLowerCase(), - color: color, - animation: animation, - enabled: true, - soundEnabled: false, - soundType: 'beep', - customSoundUrl: '' // Changed from customSound to customSoundUrl - }; - this.filters.push(filter); - this.saveFilters(); - return filter; - }, - - - // Remove a filter by ID - removeFilter: function(id) { - this.filters = this.filters.filter(f => f.id !== id); - this.saveFilters(); - }, - - // Update a filter - updateFilter: function(id, updates) { - var filter = this.filters.find(f => f.id === id); - if (filter) { - Object.assign(filter, updates); - if (updates.term) { - filter.term = updates.term.toLowerCase(); - } - this.saveFilters(); - } - }, - - // Toggle filter enabled state - toggleFilter: function(id) { - var filter = this.filters.find(f => f.id === id); - if (filter) { - filter.enabled = !filter.enabled; - this.saveFilters(); - } - }, - - // Toggle sound for filter - toggleSound: function(id) { - var filter = this.filters.find(f => f.id === id); - if (filter) { - filter.soundEnabled = !filter.soundEnabled; - this.saveFilters(); - } - }, - - // Play sound notification - playSound: function(filter) { - try { - if (filter && filter.customSoundUrl && filter.soundType === 'custom') { - // Play custom audio from URL - var audio = new Audio(filter.customSoundUrl); - audio.volume = 0.5; - audio.play().catch(e => console.warn('Custom sound failed:', e)); - } else { - // Use built-in sound based on soundType - var audioContext = new (window.AudioContext || window.webkitAudioContext)(); - var oscillator = audioContext.createOscillator(); - var gainNode = audioContext.createGain(); - - oscillator.connect(gainNode); - gainNode.connect(audioContext.destination); - - var soundType = (filter && filter.soundType) || 'beep'; - - switch(soundType) { - case 'beep': - oscillator.frequency.value = 800; - oscillator.type = 'sine'; - gainNode.gain.setValueAtTime(0, audioContext.currentTime); - gainNode.gain.linearRampToValueAtTime(0.3, audioContext.currentTime + 0.01); - gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3); - oscillator.start(audioContext.currentTime); - oscillator.stop(audioContext.currentTime + 0.3); - break; - case 'chime': - oscillator.frequency.value = 1200; - oscillator.type = 'sine'; - gainNode.gain.setValueAtTime(0, audioContext.currentTime); - gainNode.gain.linearRampToValueAtTime(0.2, audioContext.currentTime + 0.01); - gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.8); - oscillator.start(audioContext.currentTime); - oscillator.stop(audioContext.currentTime + 0.8); - break; - case 'pop': - oscillator.frequency.value = 400; - oscillator.type = 'square'; - gainNode.gain.setValueAtTime(0, audioContext.currentTime); - gainNode.gain.linearRampToValueAtTime(0.4, audioContext.currentTime + 0.01); - gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1); - oscillator.start(audioContext.currentTime); - oscillator.stop(audioContext.currentTime + 0.1); - break; - case 'ding': - oscillator.frequency.value = 1800; - oscillator.type = 'triangle'; - gainNode.gain.setValueAtTime(0, audioContext.currentTime); - gainNode.gain.linearRampToValueAtTime(0.25, audioContext.currentTime + 0.01); - gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5); - oscillator.start(audioContext.currentTime); - oscillator.stop(audioContext.currentTime + 0.5); - break; - } - } - } catch (e) { - console.warn('Sound notification failed:', e); - } - }, - - // Apply highlights to an element - highlightElement: function(element) { - if (!this.filters.length) return; - - var enabledFilters = this.filters.filter(f => f.enabled && f.term.trim()); - if (!enabledFilters.length) return; - - this.highlightTextNodes(element, enabledFilters); - }, - - // Recursively highlight text nodes - highlightTextNodes: function(element, filters) { - // Build combined regex for all filters at once - var terms = filters.map(f => this.escapeRegex(f.term)).join('|'); - if (!terms) return; - - var regex = new RegExp('(' + terms + ')', 'gi'); - - // Use faster tree walker - var walker = document.createTreeWalker( - element, - NodeFilter.SHOW_TEXT, - { - acceptNode: function(node) { - var parent = node.parentNode; - if (parent.classList && parent.classList.contains('highlight-filter')) { - return NodeFilter.FILTER_REJECT; - } - if (parent.tagName === 'SCRIPT' || parent.tagName === 'STYLE') { - return NodeFilter.FILTER_REJECT; - } - // Quick check if text contains any terms - var text = node.textContent.toLowerCase(); - for (var i = 0; i < filters.length; i++) { - if (text.indexOf(filters[i].term) !== -1) { - return NodeFilter.FILTER_ACCEPT; - } - } - return NodeFilter.FILTER_REJECT; - } - }, - false - ); - - var textNodes = []; - var node; - var maxNodes = 100; // Safety limit - var count = 0; - - while (node = walker.nextNode()) { - textNodes.push(node); - if (++count > maxNodes) break; - } - - // Process in chunks to avoid blocking - if (textNodes.length > 10) { - this.highlightInChunks(textNodes, filters, 0); - } else { - textNodes.forEach(textNode => { - this.highlightTextNode(textNode, filters); - }); - } - }, - - highlightInChunks: function(textNodes, filters, index) { - var chunkSize = 5; - var end = Math.min(index + chunkSize, textNodes.length); - - for (var i = index; i < end; i++) { - this.highlightTextNode(textNodes[i], filters); - } - - if (end < textNodes.length) { - requestAnimationFrame(() => { - this.highlightInChunks(textNodes, filters, end); - }); - } - }, - - // Highlight matches in a single text node - highlightTextNode: function(textNode, filters) { - var text = textNode.textContent; - var matches = []; - - // Find all matches - filters.forEach(filter => { - var regex = new RegExp(this.escapeRegex(filter.term), 'gi'); - var match; - while ((match = regex.exec(text)) !== null) { - matches.push({ - start: match.index, - end: match.index + match[0].length, - filter: filter, - text: match[0] - }); - - // Play sound if enabled for this filter - if (filter.soundEnabled) { - this.playSound(filter); - } - } - }); - - if (!matches.length) return; - - // Sort matches by position and remove overlaps - matches.sort((a, b) => a.start - b.start); - var cleanMatches = this.removeOverlaps(matches); - - if (!cleanMatches.length) return; - - // Create highlighted content - var result = ''; - var lastEnd = 0; - - cleanMatches.forEach(match => { - // Add text before match - result += this.escapeHtml(text.substring(lastEnd, match.start)); - - // Add highlighted match - var animationClass = match.filter.animation !== 'none' ? `highlight-${match.filter.animation}` : ''; - var style = match.filter.animation === 'slide' - ? `background-color: ${match.filter.color}; --highlight-color: ${match.filter.color};` - : match.filter.animation === 'rainbow' - ? '' // Rainbow uses its own colors - : `background-color: ${match.filter.color};`; - - result += ``; - result += this.escapeHtml(match.text); - result += ''; - - lastEnd = match.end; - }); - - // Add remaining text - result += this.escapeHtml(text.substring(lastEnd)); - - // Replace the text node with highlighted content - var wrapper = document.createElement('span'); - wrapper.innerHTML = result; - textNode.parentNode.replaceChild(wrapper, textNode); - }, - - // Remove overlapping matches (prioritize first match) - removeOverlaps: function(matches) { - var result = []; - var lastEnd = 0; - - matches.forEach(match => { - if (match.start >= lastEnd) { - result.push(match); - lastEnd = match.end; - } - }); - - return result; - }, - - // Escape regex special characters - escapeRegex: function(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - }, - - // Escape HTML - escapeHtml: function(text) { - var div = document.createElement('div'); - div.textContent = text; - return div.innerHTML; - }, - - // Show the highlight manager popup - showManager: function() { - var content = this.createManagerHTML(); - if (typeof createPopup === 'function') { - // Try to use existing createPopup function - var popup = createPopup(content, 600); - // If createPopup returns the popup element, apply smart positioning - if (popup && popup.nodeType) { - this.positionPopup(popup); - } - } else { - // Fallback popup creation with smart positioning - this.createFallbackPopup(content); - } - this.bindManagerEvents(); - }, - - // Create manager HTML - createManagerHTML: function() { - var html = ` -
- Highlight Filter Manager - × -
-
-
- ${this.createFiltersHTML()} -
-
- - - - -
-
- `; - return html; - }, - - // Create HTML for existing filters - createFiltersHTML: function() { - if (!this.filters.length) { - return '
No highlight filters configured.
Click "Add Filter" to get started!
'; - } - - return this.filters.map(filter => ` -
-
- - -
-
- -
- - - -
-
- ${filter.soundEnabled ? ` -
- - - ${filter.soundType === 'custom' ? ` - - ` : ''} -
- ` : ''} -
- `).join(''); - }, - - updateCustomSoundUrl: function(id, url) { - this.updateFilter(id, { customSoundUrl: url }); - }, - - updateSoundType: function(id, soundType) { - this.updateFilter(id, { soundType: soundType }); - if (soundType !== 'custom') { - this.updateFilter(id, { customSoundUrl: '' }); - } - this.refreshManager(); - }, - - testSound: function(id) { - var filter = this.filters.find(f => f.id === id); - if (filter) { - this.playSound(filter); - } - }, - - triggerFileUpload: function(id) { - var input = document.getElementById('customSound_' + id); - if (input) { - input.click(); - } - }, - - uploadCustomSound: function(id, input) { - var file = input.files[0]; - if (!file) return; - - if (!file.type.startsWith('audio/')) { - alert('Please select an audio file'); - return; - } - - var reader = new FileReader(); - reader.onload = (e) => { - this.updateFilter(id, { - customSound: e.target.result, - soundType: 'custom' - }); - input.value = ''; // Reset input - // Show confirmation - alert('Custom sound uploaded successfully!'); - }; - reader.readAsDataURL(file); - }, - - // Fallback popup creation - createFallbackPopup: function(content) { - var popup = document.createElement('div'); - popup.className = 'popup'; - popup.innerHTML = content; - - document.body.appendChild(popup); - - // Smart positioning to keep popup within viewport - this.positionPopup(popup); - - // Handle window resize - var resizeHandler = () => this.positionPopup(popup); - window.addEventListener('resize', resizeHandler); - - popup.querySelector('.close').onclick = function(e) { - e.preventDefault(); - window.removeEventListener('resize', resizeHandler); - document.body.removeChild(popup); - }; - }, - - // Smart popup positioning - positionPopup: function(popup) { - // Get viewport dimensions - var viewportWidth = window.innerWidth; - var viewportHeight = window.innerHeight; - - // Get popup dimensions (after it's been added to DOM) - var popupRect = popup.getBoundingClientRect(); - var popupWidth = popupRect.width || popup.offsetWidth; - var popupHeight = popupRect.height || popup.offsetHeight; - - // Calculate ideal center position - var idealLeft = (viewportWidth - popupWidth) / 2; - var idealTop = (viewportHeight - popupHeight) / 2; - - // Ensure minimum margins from edges - var margin = 10; - var left = Math.max(margin, Math.min(idealLeft, viewportWidth - popupWidth - margin)); - var top = Math.max(margin, Math.min(idealTop, viewportHeight - popupHeight - margin)); - - // Apply positioning - popup.style.left = left + 'px'; - popup.style.top = top + 'px'; - popup.style.transform = 'none'; // Remove any existing transform - - // If popup is still too tall, make it scrollable - if (popupHeight > viewportHeight - (margin * 2)) { - popup.style.maxHeight = (viewportHeight - (margin * 2)) + 'px'; - popup.style.top = margin + 'px'; - } - }, - - // Bind events for manager - bindManagerEvents: function() { - // Events are handled by inline handlers in the HTML - }, - - // Manager event handlers - addNewFilter: function() { - this.addFilter('', '#FFFF00', 'none'); - this.refreshManager(); - }, - - updateFilterTerm: function(id, term) { - this.updateFilter(id, { term: term }); - }, - - updateFilterColor: function(id, color) { - this.updateFilter(id, { color: color }); - }, - - updateFilterAnimation: function(id, animation) { - this.updateFilter(id, { animation: animation }); - }, - - toggleFilterInManager: function(id) { - this.toggleFilter(id); - this.refreshManager(); - }, - - toggleSoundInManager: function(id) { - this.toggleSound(id); - this.refreshManager(); - }, - - removeFilterFromManager: function(id) { - if (confirm('Are you sure you want to remove this highlight filter?')) { - this.removeFilter(id); - this.refreshManager(); - } - }, - - // Refresh the manager display - refreshManager: function() { - var container = document.getElementById('highlightFilters'); - if (container) { - container.innerHTML = this.createFiltersHTML(); - } - }, - - // Export filters to JSON - exportFilters: function() { - var data = JSON.stringify(this.filters, null, 2); - var blob = new Blob([data], { type: 'application/json' }); - var url = URL.createObjectURL(blob); - var a = document.createElement('a'); - a.href = url; - a.download = 'highlight_filters.json'; - a.click(); - URL.revokeObjectURL(url); - }, - - // Import filters from JSON - importFilters: function(input) { - var file = input.files[0]; - if (!file) return; - - var reader = new FileReader(); - reader.onload = (e) => { - try { - var imported = JSON.parse(e.target.result); - if (Array.isArray(imported)) { - // Validate and add filters - imported.forEach(filter => { - if (filter.term && filter.color) { - var newFilter = this.addFilter(filter.term, filter.color, filter.animation || 'none'); - if (filter.soundEnabled) { - this.updateFilter(newFilter.id, { soundEnabled: true }); - } - } - }); - this.refreshManager(); - alert('Filters imported successfully!'); - } - } catch (error) { - alert('Error importing filters: Invalid file format'); - } - }; - reader.readAsText(file); - input.value = ''; // Reset input - }, - - // Save filters to cookie - saveFilters: function() { - var data = JSON.stringify(this.filters); - try { - if (typeof setCookie === 'function') { - setCookie('highlightFilters', data, 365); - } - } catch (e) { - console.warn('Failed to save highlight filters:', e); - } - }, - - // Load filters from cookie - loadFilters: function() { - var saved = null; - - try { - if (typeof getCookie === 'function') { - saved = getCookie('highlightFilters'); - } - - if (saved) { - var parsed = JSON.parse(saved); - if (Array.isArray(parsed)) { - this.filters = parsed; - // Ensure all filters have required properties - this.filters.forEach(filter => { - if (filter.soundEnabled === undefined) { - filter.soundEnabled = false; - } - if (filter.soundType === undefined) { - filter.soundType = 'beep'; - } - // Migrate old customSound to customSoundUrl - if (filter.customSound !== undefined) { - filter.customSoundUrl = ''; - delete filter.customSound; - } - if (filter.customSoundUrl === undefined) { - filter.customSoundUrl = ''; - } - }); - } - } - } catch (e) { - console.warn('Failed to load highlight filters:', e); - } - } -}; - -// Initialize when DOM is ready -if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', function() { - highlightSystem.init(); - }); -} else { - highlightSystem.init(); -} - -window.status = 'Output'; -var $messages, $subOptions, $subAudio, $selectedSub, $contextMenu, $filterMessages, $last_message; -var opts = { - //General - 'messageCount': 0, //A count...of messages... - 'messageLimit': 200, //A limit...for the messages... - 'scrollSnapTolerance': 10, //If within x pixels of bottom - 'clickTolerance': 10, //Keep focus if outside x pixels of mousedown position on mouseup - 'imageRetryDelay': 50, //how long between attempts to reload images (in ms) - 'imageRetryLimit': 50, //how many attempts should we make? - 'popups': 0, //Amount of popups opened ever - 'wasd': false, //Is the user in wasd mode? - 'priorChatHeight': 0, //Thing for height-resizing detection - 'restarting': false, //Is the round restarting? - 'darkmode':false, //Are we using darkmode? If not WHY ARE YOU LIVING IN 2009??? - - //Options menu - 'selectedSubLoop': null, //Contains the interval loop for closing the selected sub menu - 'suppressSubClose': false, //Whether or not we should be hiding the selected sub menu - 'highlightTerms': [], - 'highlightLimit': 10, - 'highlightColor': '#FFFF00', //The color of the highlighted message - 'pingDisabled': true, //Has the user disabled the ping counter - - //Ping display - 'lastPang': 0, //Timestamp of the last response from the server. - 'pangLimit': 35000, - 'pingTime': 0, //Timestamp of when ping sent - 'pongTime': 0, //Timestamp of when ping received - 'noResponse': false, //Tracks the state of the previous ping request - 'noResponseCount': 0, //How many failed pings? - - //Clicks - 'mouseDownX': null, - 'mouseDownY': null, - 'preventFocus': false, //Prevents switching focus to the game window - - //Client Connection Data - 'clientDataLimit': 5, - 'clientData': [], - - //Admin music volume update - 'volumeUpdateDelay': 5000, //Time from when the volume updates to data being sent to the server - 'volumeUpdating': false, //True if volume update function set to fire - 'updatedVolume': 0, //The volume level that is sent to the server - 'musicStartAt': 0, //The position the music starts playing - 'musicEndAt': 0, //The position the music... stops playing... if null, doesn't apply (so the music runs through) - - 'defaultMusicVolume': 25, - - 'messageCombining': false, - - 'currentFilter': 'all', - 'customTabs': [] - -}; -var replaceRegexes = {}; - -function clamp(val, min, max) { - return Math.max(min, Math.min(val, max)) -} - -function outerHTML(el) { - var wrap = document.createElement('div'); - wrap.appendChild(el.cloneNode(true)); - return wrap.innerHTML; -} - -//Polyfill for fucking date now because of course IE8 and below don't support it -if (!Date.now) { - Date.now = function now() { - return new Date().getTime(); - }; -} -//Polyfill for trim() (IE8 and below) -if (typeof String.prototype.trim !== 'function') { - String.prototype.trim = function () { - return this.replace(/^\s+|\s+$/g, ''); - }; -} - -// Linkify the contents of a node, within its parent. -function linkify(parent, insertBefore, text) { - var start = 0; - var match; - var regex = /(?:(?:https?:\/\/)|(?:www\.))(?:[^ ]*?\.[^ ]*?)+[-A-Za-z0-9+&@#\/%?=~_|$!:,.;()]+/ig; - while ((match = regex.exec(text)) !== null) { - // add the unmatched text - parent.insertBefore(document.createTextNode(text.substring(start, match.index)), insertBefore); - - var href = match[0]; - if (!/^https?:\/\//i.test(match[0])) { - href = "http://" + match[0]; - } - - // add the link - var link = document.createElement("a"); - link.href = href; - link.textContent = match[0]; - parent.insertBefore(link, insertBefore); - - start = regex.lastIndex; - } - if (start !== 0) { - // add the remaining text and remove the original text node - parent.insertBefore(document.createTextNode(text.substring(start)), insertBefore); - parent.removeChild(insertBefore); - } -} - -// Recursively linkify the children of a given node. -function linkify_node(node) { - var children = node.childNodes; - // work backwards to avoid the risk of looping forever on our own output - for (var i = children.length - 1; i >= 0; --i) { - var child = children[i]; - if (child.nodeType == Node.TEXT_NODE) { - // text is to be linkified - linkify(node, child, child.textContent); - } else if (child.nodeName != "A" && child.nodeName != "a") { - // do not linkify existing links - linkify_node(child); - } - } -} - -//Shit fucking piece of crap that doesn't work god fuckin damn it -function linkify_fallback(text) { - var rex = /((?:'+$0+''; - } - else { - return $1 ? $0: ''+$0+''; - } - }); -} - -function byondDecode(message) { - // Basically we url_encode twice server side so we can manually read the encoded version and actually do UTF-8. - // The replace for + is because FOR SOME REASON, BYOND replaces spaces with a + instead of %20, and a plus with %2b. - // Marvelous. - message = message.replace(/\+/g, "%20"); - try { - // This is a workaround for the above not always working when BYOND's shitty url encoding breaks. (byond bug id:2399401) - if (decodeURIComponent) { - message = decodeURIComponent(message); - } else { - throw new Error("Easiest way to trigger the fallback") - } - } catch (err) { - message = unescape(message); - } - return message; -} - -function replaceRegex() { - var selectedRegex = replaceRegexes[$(this).attr('replaceRegex')]; - if (selectedRegex) { - var replacedText = $(this).html().replace(selectedRegex[0], selectedRegex[1]); - $(this).html(replacedText); - } - $(this).removeAttr('replaceRegex'); -} - -//Actually turns the highlight term match into appropriate html -function addHighlightMarkup(match) { - var extra = ''; - if (opts.highlightColor) { - extra += ' style="background-color: '+opts.highlightColor+'"'; - } - return ''+match+''; -} - -//Highlights words based on user settings -function highlightTerms(el) { - if (window.highlightSystem) { - highlightSystem.highlightElement(el); - } else { - // Fallback to old system if new one isn't loaded - legacyHighlightTerms(el); - } -} - -function legacyHighlightTerms(el) { - if (el.children.length > 0) { - for(var h = 0; h < el.children.length; h++){ - legacyHighlightTerms(el.children[h]); - } - } - - var hasTextNode = false; - for (var node = 0; node < el.childNodes.length; node++) { - if (el.childNodes[node].nodeType === 3) { - hasTextNode = true; - break; - } - } - - if (hasTextNode) { - var newText = ''; - for (var c = 0; c < el.childNodes.length; c++) { - if (el.childNodes[c].nodeType === 3) { - var words = el.childNodes[c].data.split(' '); - for (var w = 0; w < words.length; w++) { - var newWord = null; - for (var i = 0; i < opts.highlightTerms.length; i++) { - if (opts.highlightTerms[i] && words[w].toLowerCase().indexOf(opts.highlightTerms[i].toLowerCase()) > -1) { - newWord = words[w].replace("<", "<").replace(new RegExp(opts.highlightTerms[i], 'gi'), addHighlightMarkup); - break; - } - } - newText += newWord || words[w].replace("<", "<"); - newText += w >= words.length ? '' : ' '; - } - } else { - newText += outerHTML(el.childNodes[c]); - } - } - el.innerHTML = newText; - } -} - -function iconError(E) { - var that = this; - setTimeout(function() { - var attempts = $(that).data('reload_attempts'); - if (typeof attempts === 'undefined' || !attempts) { - attempts = 1; - } - if (attempts > opts.imageRetryLimit) - return; - var src = that.src; - that.src = null; - that.src = src+'#'+attempts; - $(that).data('reload_attempts', ++attempts); - }, opts.imageRetryDelay); -} - -//Send a message to the client -function output(message, flag) { - if (typeof message === 'undefined') { - return; - } - if (typeof flag === 'undefined') { - flag = ''; - } - - if (flag !== 'internal') opts.lastPang = Date.now(); - - // Send to WebSocket if available - if (flag !== 'internal' && typeof window.WebSocketManager !== 'undefined') { - try { - var tempDiv = document.createElement('div'); - tempDiv.innerHTML = byondDecode(message).trim(); - var plainText = tempDiv.textContent || tempDiv.innerText || ""; - - var payload = JSON.stringify({ - content: { - html: message, - text: plainText, - timestamp: Date.now(), - flag: flag - } - }); - - window.WebSocketManager.sendMessage('chat/message', payload); - } catch (e) { - console.warn('WebSocket send failed:', e); - } - } - - // Add to queue instead of processing immediately - messageQueue.add(message, flag); -} - - - -// Highlighting function (fixed) -function highlightTerms(element) { - if (!opts.highlightTerms || opts.highlightTerms.length === 0) return; - - function highlightInTextNode(textNode) { - var text = textNode.textContent; - var highlightedText = text; - - opts.highlightTerms.forEach(term => { - if (term && term.trim()) { - var regex = new RegExp(`(${escapeRegex(term.trim())})`, 'gi'); - highlightedText = highlightedText.replace(regex, - `$1`); - } - }); - - if (highlightedText !== text) { - var wrapper = document.createElement('span'); - wrapper.innerHTML = highlightedText; - textNode.parentNode.replaceChild(wrapper, textNode); - } - } - - function escapeRegex(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - - // Walk through all text nodes - var walker = document.createTreeWalker( - element, - NodeFilter.SHOW_TEXT, - null, - false - ); - - var textNodes = []; - var node; - while (node = walker.nextNode()) { - textNodes.push(node); - } - - textNodes.forEach(highlightInTextNode); -} -class WebSocketManager { - constructor() { - this.websocket = null; - this.settings = { - websocketEnabled: false, - websocketServer: 'localhost:1234' - }; - this.WEBSOCKET_DISABLED = 4555; - this.WEBSOCKET_REATTEMPT = 4556; - this.reconnectAttempts = 0; - this.maxReconnectAttempts = 5; - - this.loadSettings(); - this.initializeUI(); - } - - // Send WebSocket notices to chat - sendWSNotice(message, small = false) { - const html = small - ? `${message}` - : `
${message}
`; - - // Assuming you have a chat renderer function - if (typeof processChatMessage === 'function') { - processChatMessage({ html: html }); - } else { - // Fallback: append directly to messages - const messagesDiv = document.getElementById('messages'); - if (messagesDiv) { - const messageElement = document.createElement('div'); - messageElement.innerHTML = html; - messagesDiv.appendChild(messageElement); - messagesDiv.scrollTop = messagesDiv.scrollHeight; - } - } - } - - // Update WebSocket status indicator - updateStatus(status, message = '') { - const statusElement = document.getElementById('websocketStatus'); - if (statusElement) { - statusElement.className = `websocket-status ${status}`; - statusElement.textContent = message || status.charAt(0).toUpperCase() + status.slice(1); - } - } - - // Setup WebSocket connection - setupWebsocket() { - if (!this.settings.websocketEnabled) { - if (this.websocket) { - this.websocket.close(this.WEBSOCKET_REATTEMPT); - this.websocket = null; - } - this.updateStatus('disconnected'); - return; - } - - // Close existing connection - if (this.websocket) { - this.websocket.close(this.WEBSOCKET_REATTEMPT); - } - - this.updateStatus('connecting'); - - try { - this.websocket = new WebSocket(`ws://${this.settings.websocketServer}`); - } catch (e) { - if (e.name === 'SyntaxError') { - this.sendWSNotice( - `Error creating websocket: Invalid address! Make sure you're following the placeholder. Example: localhost:1234` - ); - this.updateStatus('disconnected', 'Invalid Address'); - return; - } - this.sendWSNotice(`Error creating websocket: ${e.name} - ${e.message}`); - this.updateStatus('disconnected', 'Connection Error'); - return; - } - - this.websocket.addEventListener('open', () => { - this.sendWSNotice('Websocket connected!', true); - this.updateStatus('connected'); - this.reconnectAttempts = 0; - }); - - this.websocket.addEventListener('close', (ev) => { - if (!this.settings.websocketEnabled) { - this.updateStatus('disconnected'); - return; - } - - if (ev.code !== this.WEBSOCKET_DISABLED && ev.code !== this.WEBSOCKET_REATTEMPT) { - this.sendWSNotice( - `Websocket disconnected! Code: ${ev.code} Reason: ${ev.reason || 'None provided'}` - ); - this.updateStatus('disconnected', 'Connection Lost'); - - // Auto-reconnect logic - if (this.settings.websocketEnabled && this.reconnectAttempts < this.maxReconnectAttempts) { - this.reconnectAttempts++; - setTimeout(() => { - this.sendWSNotice(`Attempting to reconnect... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`, true); - this.setupWebsocket(); - }, 2000 * this.reconnectAttempts); - } - } else { - this.updateStatus('disconnected'); - } - }); - - this.websocket.addEventListener('error', (error) => { - console.error('WebSocket error:', error); - this.updateStatus('disconnected', 'Connection Error'); - }); - - // Handle incoming messages - this.websocket.addEventListener('message', (event) => { - try { - const data = JSON.parse(event.data); - this.handleWebSocketMessage(data); - } catch (e) { - console.error('Error parsing WebSocket message:', e); - } - }); - } - - // Handle incoming WebSocket messages - handleWebSocketMessage(data) { - // Process incoming messages based on type - console.log('Received WebSocket message:', data); - - // You can extend this to handle different message types - if (data.type === 'chat/message') { - // Handle chat messages - this.sendWSNotice(data.message, data.small || false); - } else if (data.type === 'system/message') { - // Handle system messages - this.sendWSNotice(data.message, true); - } - } - - // Send message through WebSocket - sendMessage(type, payload) { - if (this.websocket && this.websocket.readyState === WebSocket.OPEN) { - this.websocket.send(JSON.stringify({ - type: type, - payload: payload - })); - return true; - } - return false; - } - - // Connect WebSocket - connect() { - this.settings.websocketEnabled = true; - this.saveSettings(); - this.sendWSNotice('Websocket enabled.', true); - this.setupWebsocket(); - } - - // Disconnect WebSocket - disconnect() { - this.settings.websocketEnabled = false; - this.saveSettings(); - if (this.websocket) { - this.websocket.close(this.WEBSOCKET_DISABLED); - this.websocket = null; - } - this.sendWSNotice('Websocket forcefully disconnected.', true); - this.updateStatus('disconnected'); - } - - // Reconnect WebSocket - reconnect() { - if (this.settings.websocketEnabled) { - this.reconnectAttempts = 0; - this.setupWebsocket(); - } - } - - // Update server address - updateServer(server) { - this.settings.websocketServer = server; - this.saveSettings(); - - if (this.settings.websocketEnabled) { - if (this.websocket) { - this.websocket.close(this.WEBSOCKET_REATTEMPT, 'Websocket settings changed'); - } - this.setupWebsocket(); - } - } - - // Save settings to localStorage - saveSettings() { - try { - localStorage.setItem('websocketSettings', JSON.stringify(this.settings)); - } catch (e) { - console.error('Failed to save WebSocket settings:', e); - } - - // Update UI - const enabledCheckbox = document.getElementById('websocketEnabled'); - const serverInput = document.getElementById('websocketServer'); - - if (enabledCheckbox) { - enabledCheckbox.checked = this.settings.websocketEnabled; - } - if (serverInput) { - serverInput.value = this.settings.websocketServer; - } - } - - // Load settings from localStorage - loadSettings() { - try { - const saved = localStorage.getItem('websocketSettings'); - if (saved) { - this.settings = { ...this.settings, ...JSON.parse(saved) }; - } - } catch (e) { - console.error('Failed to load WebSocket settings:', e); - } - } - - // Initialize UI event listeners - initializeUI() { - // Wait for DOM to be ready - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', () => this.setupUIListeners()); - } else { - this.setupUIListeners(); - } - } - - setupUIListeners() { - // WebSocket toggle button - const toggleWebsocket = document.getElementById('toggleWebsocket'); - if (toggleWebsocket) { - toggleWebsocket.addEventListener('click', (e) => { - e.preventDefault(); - const subWebsocket = document.getElementById('subWebsocket'); - if (subWebsocket) { - subWebsocket.style.display = subWebsocket.style.display === 'block' ? 'none' : 'block'; - } - }); - } - - // Enable/disable checkbox - const enabledCheckbox = document.getElementById('websocketEnabled'); - if (enabledCheckbox) { - enabledCheckbox.checked = this.settings.websocketEnabled; - enabledCheckbox.addEventListener('change', (e) => { - if (e.target.checked) { - this.connect(); - } else { - this.disconnect(); - } - }); - } - - // Server input - const serverInput = document.getElementById('websocketServer'); - if (serverInput) { - serverInput.value = this.settings.websocketServer; - serverInput.addEventListener('change', (e) => { - this.updateServer(e.target.value); - }); - serverInput.addEventListener('keypress', (e) => { - if (e.key === 'Enter') { - this.updateServer(e.target.value); - } - }); - } - - // Control buttons - const connectBtn = document.getElementById('connectWebsocket'); - const disconnectBtn = document.getElementById('disconnectWebsocket'); - const reconnectBtn = document.getElementById('reconnectWebsocket'); - - if (connectBtn) { - connectBtn.addEventListener('click', () => this.connect()); - } - if (disconnectBtn) { - disconnectBtn.addEventListener('click', () => this.disconnect()); - } - if (reconnectBtn) { - reconnectBtn.addEventListener('click', () => this.reconnect()); - } - - // Initialize connection if enabled - if (this.settings.websocketEnabled) { - setTimeout(() => this.setupWebsocket(), 1000); - } - } - } - - // Initialize WebSocket Manager - const wsManager = new WebSocketManager(); - - // Make it globally accessible for integration with existing chat system - window.WebSocketManager = wsManager; - - // Example integration with existing chat system - // You can call these functions from your existing browserOutput.js - window.sendWebSocketMessage = function(type, payload) { - return wsManager.sendMessage(type, payload); - }; - - window.getWebSocketStatus = function() { - return wsManager.websocket ? wsManager.websocket.readyState : WebSocket.CLOSED; - }; - -// Fixed filter function that looks at nested elements for chat classes -function applyFilterToMessage(messageElement) { - if (!messageElement) return; - - var shouldShow = false; - - // Fast path - if (opts.currentFilter === 'all') { - shouldShow = true; - } else { - // Check cache first - var cacheKey = messageElement.className + messageElement.innerHTML.substring(0, 100); - if (filterCache.has(cacheKey)) { - shouldShow = filterCache.get(cacheKey); - } else { - // Compute and cache - var classes = messageElement.className.split(' '); - var innerHTML = messageElement.innerHTML; - - shouldShow = classes.indexOf(opts.currentFilter) !== -1 || - innerHTML.indexOf('class="' + opts.currentFilter) !== -1; - - if (!shouldShow && opts.customTabs) { - for (var i = 0; i < opts.customTabs.length; i++) { - var tab = opts.customTabs[i]; - if (tab.name.toLowerCase() === opts.currentFilter) { - for (var j = 0; j < tab.classes.length; j++) { - if (classes.indexOf(tab.classes[j]) !== -1 || - innerHTML.indexOf('class="' + tab.classes[j]) !== -1) { - shouldShow = true; - break; - } - } - break; - } - } - } - - // Cache result - filterCache.set(cacheKey, shouldShow); - } - } - - // Apply visibility - if (shouldShow) { - messageElement.classList.remove('filtered-hidden'); - if (messageElement.style.display === 'none') { - messageElement.style.display = ''; - } - } else { - messageElement.classList.add('filtered-hidden'); - messageElement.style.display = 'none'; - } -} - - -var filterCache = new Map(); - -function switchFilter(filterName) { - console.log('Switching to filter:', filterName); - opts.currentFilter = filterName.toLowerCase(); - - // Update tab appearance - $('.filter-tab').removeClass('active'); - $(`.filter-tab[data-filter="${filterName.toLowerCase()}"]`).addClass('active'); - - // Clear cache when switching filters - filterCache.clear(); - - // Use DocumentFragment for better performance - var entries = document.querySelectorAll('#messages .entry'); - - // Batch DOM updates - requestAnimationFrame(() => { - entries.forEach(entry => { - applyFilterToMessage(entry); - }); - }); - - setCookie('currentFilter', filterName, 365); -} - - -// Custom tab functions -function showAddTabForm() { - $('#addTabForm').show(); -} - -function cancelAddTab() { - $('#addTabForm').hide(); - $('#tabName').val(''); - $('#tabClasses').val(''); -} - -function saveCustomTab() { - var name = $('#tabName').val().trim(); - var classesStr = $('#tabClasses').val().trim(); - - if (!name || !classesStr) { - alert('Please fill in both fields'); - return; - } - - var classes = classesStr.split(',').map(c => c.trim()).filter(c => c); - var newTab = { name: name, classes: classes }; - - opts.customTabs.push(newTab); - - // Add tab to UI - var tabElement = $(`
${name} ×
`); - $('#addTabBtn').before(tabElement); - - // Save to cookie - setCookie('customTabs', JSON.stringify(opts.customTabs), 365); - - cancelAddTab(); -} - -function removeCustomTab(tabName) { - opts.customTabs = opts.customTabs.filter(tab => tab.name.toLowerCase() !== tabName.toLowerCase()); - $(`.filter-tab[data-filter="${tabName.toLowerCase()}"]`).remove(); - setCookie('customTabs', JSON.stringify(opts.customTabs), 365); - - // Switch to 'all' if we removed the active tab - if (opts.currentFilter === tabName.toLowerCase()) { - switchFilter('all'); - } -} - -// Popup functions -function createPopup(content, width) { - var popup = $(``); - $('body').append(popup); - - popup.on('click', '.close', function(e) { - e.preventDefault(); - popup.remove(); - }); -} - -function showHighlightPopup() { - var termInputs = ''; - for (var i = 0; i < 10; i++) { - termInputs += `
`; - } - - var popupContent = ` -
String Highlighting
-
Enter terms to highlight in chat messages:
-
- ${termInputs} -
- - -
- -
- `; - - createPopup(popupContent, 350); -} - -function internalOutput(message, flag) -{ - output(escaper(message), flag) -} - -//Runs a route within byond, client or server side. Consider this "ehjax" for byond. -function runByond(uri) { - window.location = uri; -} - -function setCookie(cname, cvalue, exdays) { - cvalue = escaper(cvalue); - var d = new Date(); - d.setTime(d.getTime() + (exdays*24*60*60*1000)); - var expires = 'expires='+d.toUTCString(); - document.cookie = cname + '=' + cvalue + '; ' + expires + "; path=/"; -} - -function getCookie(cname) { - var name = cname + '='; - var ca = document.cookie.split(';'); - for(var i=0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1); - if (c.indexOf(name) === 0) { - return decoder(c.substring(name.length,c.length)); - } - } - return ''; -} - -function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B);} -function toHex(n) { - n = parseInt(n,10); - if (isNaN(n)) return "00"; - n = Math.max(0,Math.min(n,255)); - return "0123456789ABCDEF".charAt((n-n%16)/16) + "0123456789ABCDEF".charAt(n%16); -} - -function swap() { //Swap to darkmode - if (opts.darkmode){ - document.getElementById("sheetofstyles").href = "browserOutput.css"; - opts.darkmode = false; - runByond('?_src_=chat&proc=swaptolightmode'); - } else { - document.getElementById("sheetofstyles").href = "browserOutput.css"; - opts.darkmode = true; - runByond('?_src_=chat&proc=swaptodarkmode'); - } - setCookie('darkmode', (opts.darkmode ? 'true' : 'false'), 365); -} - -function handleClientData(ckey, ip, compid) { - //byond sends player info to here - var currentData = {'ckey': ckey, 'ip': ip, 'compid': compid}; - if (opts.clientData && !$.isEmptyObject(opts.clientData)) { - runByond('?_src_=chat&proc=analyzeClientData¶m[cookie]='+JSON.stringify({'connData': opts.clientData})); - - for (var i = 0; i < opts.clientData.length; i++) { - var saved = opts.clientData[i]; - if (currentData.ckey == saved.ckey && currentData.ip == saved.ip && currentData.compid == saved.compid) { - return; //Record already exists - } - } - - if (opts.clientData.length >= opts.clientDataLimit) { - opts.clientData.shift(); - } - } else { - runByond('?_src_=chat&proc=analyzeClientData¶m[cookie]=none'); - } - - //Update the cookie with current details - opts.clientData.push(currentData); - setCookie('connData', JSON.stringify(opts.clientData), 365); -} - -//Server calls this on ehjax response -//Or, y'know, whenever really -function ehjaxCallback(data) { - opts.lastPang = Date.now(); - if (data == 'softPang') { - return; - } else if (data == 'pang') { - opts.pingCounter = 0; //reset - opts.pingTime = Date.now(); - runByond('?_src_=chat&proc=ping'); - - } else if (data == 'pong') { - if (opts.pingDisabled) {return;} - opts.pongTime = Date.now(); - var pingDuration = Math.ceil((opts.pongTime - opts.pingTime) / 2); - $('#pingMs').text(pingDuration+'ms'); - pingDuration = Math.min(pingDuration, 255); - var red = pingDuration; - var green = 255 - pingDuration; - var blue = 0; - var hex = rgbToHex(red, green, blue); - $('#pingDot').css('color', '#'+hex); - - } else if (data == 'roundrestart') { - opts.restarting = true; - internalOutput('
The connection has been closed because the server is restarting. Please wait while you automatically reconnect.
', 'internal'); - } else if (data == 'stopMusic') { - $('#adminMusic').prop('src', ''); - } else { - //Oh we're actually being sent data instead of an instruction - var dataJ; - try { - dataJ = $.parseJSON(data); - } catch (e) { - //But...incorrect :sadtrombone: - window.onerror('JSON: '+e+'. '+data, 'browserOutput.html', 327); - return; - } - data = dataJ; - - if (data.clientData) { - if (opts.restarting) { - opts.restarting = false; - $('.connectionClosed.restarting:not(.restored)').addClass('restored').text('The round restarted and you successfully reconnected!'); - } - if (!data.clientData.ckey && !data.clientData.ip && !data.clientData.compid) { - //TODO: Call shutdown perhaps - return; - } else { - handleClientData(data.clientData.ckey, data.clientData.ip, data.clientData.compid); - } - sendVolumeUpdate(); - } else if (data.adminMusic) { - if (typeof data.adminMusic === 'string') { - var adminMusic = byondDecode(data.adminMusic); - var bindLoadedData = false; - adminMusic = adminMusic.match(/https?:\/\/\S+/) || ''; - if (data.musicRate) { - var newRate = Number(data.musicRate); - if(newRate) { - $('#adminMusic').prop('defaultPlaybackRate', newRate); - } - } else { - $('#adminMusic').prop('defaultPlaybackRate', 1.0); - } - if (data.musicSeek) { - opts.musicStartAt = Number(data.musicSeek) || 0; - bindLoadedData = true; - } else { - opts.musicStartAt = 0; - } - if (data.musicHalt) { - opts.musicEndAt = Number(data.musicHalt) || null; - bindLoadedData = true; - } - if (bindLoadedData) { - $('#adminMusic').one('loadeddata', adminMusicLoadedData); - } - $('#adminMusic').prop('src', adminMusic); - $('#adminMusic').trigger("play"); - } - } else if (data.syncRegex) { - for (var i in data.syncRegex) { - - var regexData = data.syncRegex[i]; - var regexName = regexData[0]; - var regexFlags = regexData[1]; - var regexReplaced = regexData[2]; - - replaceRegexes[i] = [new RegExp(regexName, regexFlags), regexReplaced]; - } - } - } -} - -function createPopup(contents, width) { - opts.popups++; - $('body').append(''); - - //Attach close popup event - var $popup = $('#popup'+opts.popups); - var height = $popup.outerHeight(); - $popup.css({'height': height+'px', 'margin': '-'+(height/2)+'px 0 0 -'+(width/2)+'px'}); - - $popup.on('click', '.close', function(e) { - e.preventDefault(); - $popup.remove(); - }); -} - -function toggleWasd(state) { - opts.wasd = (state == 'on' ? true : false); -} - -function sendVolumeUpdate() { - opts.volumeUpdating = false; - if(opts.updatedVolume) { - runByond('?_src_=chat&proc=setMusicVolume¶m[volume]='+opts.updatedVolume); - } -} - -function adminMusicEndCheck(event) { - if (opts.musicEndAt) { - if ($('#adminMusic').prop('currentTime') >= opts.musicEndAt) { - $('#adminMusic').off(event); - $('#adminMusic').trigger('pause'); - $('#adminMusic').prop('src', ''); - } - } else { - $('#adminMusic').off(event); - } -} - -function adminMusicLoadedData(event) { - if (opts.musicStartAt && ($('#adminMusic').prop('duration') === Infinity || (opts.musicStartAt <= $('#adminMusic').prop('duration'))) ) { - $('#adminMusic').prop('currentTime', opts.musicStartAt); - } - if (opts.musicEndAt) { - $('#adminMusic').on('timeupdate', adminMusicEndCheck); - } -} - -function subSlideUp() { - $(this).removeClass('scroll'); - $(this).css('height', ''); -} - -function startSubLoop() { - if (opts.selectedSubLoop) { - clearInterval(opts.selectedSubLoop); - } - return setInterval(function() { - if (!opts.suppressSubClose && $selectedSub.is(':visible')) { - $selectedSub.slideUp('fast', subSlideUp); - clearInterval(opts.selectedSubLoop); - } - }, 5000); //every 5 seconds -} - -function handleToggleClick($sub, $toggle) { - if ($selectedSub !== $sub && $selectedSub.is(':visible')) { - $selectedSub.slideUp('fast', subSlideUp); - } - $selectedSub = $sub - if ($selectedSub.is(':visible')) { - $selectedSub.slideUp('fast', subSlideUp); - clearInterval(opts.selectedSubLoop); - } else { - $selectedSub.slideDown('fast', function() { - var windowHeight = $(window).height(); - var toggleHeight = $toggle.outerHeight(); - var priorSubHeight = $selectedSub.outerHeight(); - var newSubHeight = windowHeight - toggleHeight; - $(this).height(newSubHeight); - if (priorSubHeight > (windowHeight - toggleHeight)) { - $(this).addClass('scroll'); - } - }); - opts.selectedSubLoop = startSubLoop(); - } -} - - -/***************************************** -* -* DOM READY -* -******************************************/ - -if (typeof $ === 'undefined') { - var div = document.getElementById('loading').childNodes[1]; - div += '

ERROR: Jquery did not load.'; -} - -$(function() { - $messages = $('#messages'); - $subOptions = $('#subOptions'); - $subAudio = $('#subAudio'); - $selectedSub = $subOptions; - - //Hey look it's a controller loop! - setInterval(function() { - if (opts.lastPang + opts.pangLimit < Date.now() && !opts.restarting) { //Every pingLimit - if (!opts.noResponse) { //Only actually append a message if the previous ping didn't also fail (to prevent spam) - opts.noResponse = true; - opts.noResponseCount++; - internalOutput('
You are either AFK, experiencing lag or the connection has closed.
', 'internal'); - } - } else if (opts.noResponse) { //Previous ping attempt failed ohno - $('.connectionClosed[data-count="'+opts.noResponseCount+'"]:not(.restored)').addClass('restored').text('Your connection has been restored (probably)!'); - opts.noResponse = false; - } - }, 2000); //2 seconds - - - /***************************************** - * - * LOAD SAVED CONFIG - * - ******************************************/ - var savedConfig = { - fontsize: getCookie('fontsize'), - 'spingDisabled': getCookie('pingdisabled'), - 'smusicVolume': getCookie('musicVolume'), - 'smessagecombining': getCookie('messagecombining'), - 'sdarkmode': getCookie('darkmode'), - }; - - var savedFilter = getCookie('currentFilter'); - if (savedFilter) { - opts.currentFilter = savedFilter; - } - - var savedCustomTabs = getCookie('customTabs'); - if (savedCustomTabs) { - try { - opts.customTabs = JSON.parse(savedCustomTabs); - // Recreate custom tabs in UI - opts.customTabs.forEach(tab => { - var tabElement = $(`
${tab.name} ×
`); - $('#addTabBtn').before(tabElement); - }); - } catch (e) { - console.log('Error loading custom tabs:', e); - } - } - - // Set initial filter - if (opts.currentFilter && opts.currentFilter !== 'all') { - switchFilter(opts.currentFilter); - } - if (savedConfig.fontsize) { - $messages.css('font-size', savedConfig.fontsize); - internalOutput('Loaded font size setting of: '+savedConfig.fontsize+'', 'internal'); - } - if(savedConfig.sdarkmode == 'true'){ - swap(); - } - if (savedConfig.spingDisabled) { - if (savedConfig.spingDisabled == 'true') { - opts.pingDisabled = true; - $('#ping').hide(); - } - internalOutput('Loaded ping display of: '+(opts.pingDisabled ? 'hidden' : 'visible')+'', 'internal'); - } - if (savedConfig.smusicVolume) { - var newVolume = clamp(savedConfig.smusicVolume, 0, 100); - $('#adminMusic').prop('volume', newVolume / 100); - $('#musicVolume').val(newVolume); - opts.updatedVolume = newVolume; - sendVolumeUpdate(); - internalOutput('Loaded music volume of: '+savedConfig.smusicVolume+'', 'internal'); - } - else{ - $('#adminMusic').prop('volume', opts.defaultMusicVolume / 100); - } - - if (savedConfig.smessagecombining) { - if (savedConfig.smessagecombining == 'false') { - opts.messageCombining = false; - } else { - opts.messageCombining = true; - } - } - (function() { - var dataCookie = getCookie('connData'); - if (dataCookie) { - var dataJ; - try { - dataJ = $.parseJSON(dataCookie); - } catch (e) { - window.onerror('JSON '+e+'. '+dataCookie, 'browserOutput.html', 434); - return; - } - opts.clientData = dataJ; - } - })(); - - - /***************************************** - * - * BASE CHAT OUTPUT EVENTS - * - ******************************************/ - - $('body').on('click', 'a', function(e) { - e.preventDefault(); - }); - - $('body').on('mousedown', function(e) { - var $target = $(e.target); - - if ($contextMenu) { - $contextMenu.hide(); - return false; - } - - if ($target.is('a') || $target.parent('a').length || $target.is('input') || $target.is('textarea')) { - opts.preventFocus = true; - } else { - opts.preventFocus = false; - opts.mouseDownX = e.pageX; - opts.mouseDownY = e.pageY; - } - }); - - $messages.on('mousedown', function(e) { - if ($selectedSub && $selectedSub.is(':visible')) { - $selectedSub.slideUp('fast', subSlideUp); - clearInterval(opts.selectedSubLoop); - } - }); - - $('body').on('mouseup', function(e) { - if (!opts.preventFocus && - (e.pageX >= opts.mouseDownX - opts.clickTolerance && e.pageX <= opts.mouseDownX + opts.clickTolerance) && - (e.pageY >= opts.mouseDownY - opts.clickTolerance && e.pageY <= opts.mouseDownY + opts.clickTolerance) - ) { - opts.mouseDownX = null; - opts.mouseDownY = null; - runByond('byond://winset?mapwindow.map.focus=true'); - } - }); - - $messages.on('click', 'a', function(e) { - var href = $(this).attr('href'); - $(this).addClass('visited'); - if (href[0] == '?' || (href.length >= 8 && href.substring(0,8) == 'byond://')) { - runByond(href); - } else { - href = escaper(href); - runByond('?action=openLink&link='+href); - } - }); - - //Fuck everything about this event. Will look into alternatives. - $('body').on('keydown', function(e) { - if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA') { - return; - } - - if (e.ctrlKey || e.altKey || e.shiftKey) { //Band-aid "fix" for allowing ctrl+c copy paste etc. Needs a proper fix. - return; - } - - e.preventDefault() - - var k = e.which; - // Hardcoded because else there would be no feedback message. - if (k == 113) { // F2 - runByond('byond://winset?screenshot=auto'); - internalOutput('Screenshot taken', 'internal'); - } - - var c = ""; - switch (k) { - case 8: - c = 'BACK'; - case 9: - c = 'TAB'; - case 13: - c = 'ENTER'; - case 19: - c = 'PAUSE'; - case 27: - c = 'ESCAPE'; - case 33: // Page up - c = 'NORTHEAST'; - case 34: // Page down - c = 'SOUTHEAST'; - case 35: // End - c = 'SOUTHWEST'; - case 36: // Home - c = 'NORTHWEST'; - case 37: - c = 'WEST'; - case 38: - c = 'NORTH'; - case 39: - c = 'EAST'; - case 40: - c = 'SOUTH'; - case 45: - c = 'INSERT'; - case 46: - c = 'DELETE'; - case 93: // That weird thing to the right of alt gr. - c = 'APPS'; - - default: - c = String.fromCharCode(k); - } - - if (c.length == 0) { - if (!e.shiftKey) { - c = c.toLowerCase(); - } - runByond('byond://winset?mapwindow.map.focus=true;mainwindow.input.text='+c); - return false; - } else { - runByond('byond://winset?mapwindow.map.focus=true'); - return false; - } - }); - - //Mildly hacky fix for scroll issues on mob change (interface gets resized sometimes, messing up snap-scroll) - $(window).on('resize', function(e) { - if ($(this).height() !== opts.priorChatHeight) { - $('body,html').scrollTop($messages.outerHeight()); - opts.priorChatHeight = $(this).height(); - } - }); - - - /***************************************** - * - * OPTIONS INTERFACE EVENTS - * - ******************************************/ - - $('body').on('click', '#newMessages', function(e) { - var messagesHeight = $messages.outerHeight(); - $('body,html').scrollTop(messagesHeight); - $('#newMessages').remove(); - runByond('byond://winset?mapwindow.map.focus=true'); - }); - - // Filter tab click handlers - $(document).on('click', '.filter-tab', function(e) { - e.preventDefault(); - var filterName = $(this).data('filter'); - switchFilter(filterName); - }); - - $(document).on('click', '#addTabBtn', function(e) { - e.preventDefault(); - showAddTabForm(); - }); - - $(document).on('click', '.remove-tab', function(e) { - e.preventDefault(); - e.stopPropagation(); - var tabName = $(this).parent().data('filter'); - removeCustomTab(tabName); - }); - - $('#toggleOptions').click(function(e) { - handleToggleClick($subOptions, $(this)); - }); - $('#darkmodetoggle').click(function(e) { - swap(); - }); - $('#toggleAudio').click(function(e) { - handleToggleClick($subAudio, $(this)); - }); - - $('.sub, .toggle').mouseenter(function() { - opts.suppressSubClose = true; - }); - - $('.sub, .toggle').mouseleave(function() { - opts.suppressSubClose = false; - }); - - $('#decreaseFont').click(function(e) { - savedConfig.fontsize = Math.max(parseInt(savedConfig.fontsize || 13) - 1, 1) + 'px'; - $messages.css({'font-size': savedConfig.fontsize}); - setCookie('fontsize', savedConfig.fontsize, 365); - internalOutput('Font size set to '+savedConfig.fontsize+'', 'internal'); - }); - - $('#increaseFont').click(function(e) { - savedConfig.fontsize = (parseInt(savedConfig.fontsize || 13) + 1) + 'px'; - $messages.css({'font-size': savedConfig.fontsize}); - setCookie('fontsize', savedConfig.fontsize, 365); - internalOutput('Font size set to '+savedConfig.fontsize+'', 'internal'); - }); - - $('#togglePing').click(function(e) { - if (opts.pingDisabled) { - $('#ping').slideDown('fast'); - opts.pingDisabled = false; - } else { - $('#ping').slideUp('fast'); - opts.pingDisabled = true; - } - setCookie('pingdisabled', (opts.pingDisabled ? 'true' : 'false'), 365); - }); - - $('#saveLog').click(function(e) { - var date = new Date(); - var fname = ' Vanderlin Chat Log ' + - date.getFullYear() + '-' + - (date.getMonth() + 1 < 10 ? '0' : '') + (date.getMonth() + 1) + '-' + - (date.getDate() < 10 ? '0' : '') + date.getDate() + ' ' + - (date.getHours() < 10 ? '0' : '') + date.getHours() + - (date.getMinutes() < 10 ? '0' : '') + date.getMinutes() + - (date.getSeconds() < 10 ? '0' : '') + date.getSeconds() + - '.html'; - - $.ajax({ - type: 'GET', - url: 'browserOutput_white.css', - success: function(styleData) { - var blob = new Blob([ - 'Vanderlin Chat Log', - $messages.html(), - '' - ], { type: 'text/html;charset=utf-8' }); - - if (window.navigator.msSaveBlob) { - window.navigator.msSaveBlob(blob, fname); - } else { - var link = document.createElement('a'); - link.href = URL.createObjectURL(blob); - link.download = fname; - link.click(); - URL.revokeObjectURL(link.href); - } - }, - }); - }); - - highlightSystem.init(); - $('#highlightTerm').off('click').on('click', function(e) { - e.preventDefault(); - - if (window.highlightSystem) { - highlightSystem.showManager(); - } else { - // Fallback to old popup if new system isn't available - showLegacyHighlightPopup(); - } - }); - - // Initialize the new highlight system - if (window.highlightSystem) { - highlightSystem.init(); - - // Migrate old highlight terms to new system - if (opts.highlightTerms && opts.highlightTerms.length > 0) { - opts.highlightTerms.forEach(function(term) { - if (term && term.trim()) { - highlightSystem.addFilter(term, opts.highlightColor || '#FFFF00', 'none'); - } - }); - - // Clear old terms to avoid duplication - opts.highlightTerms = []; - setCookie('highlightterms', JSON.stringify([]), 365); - } - }; - - $('#clearMessages').click(function() { - $messages.empty(); - opts.messageCount = 0; - }); - - $('#musicVolumeSpan').hover(function() { - $('#musicVolumeText').addClass('hidden'); - $('#musicVolume').removeClass('hidden'); - }, function() { - $('#musicVolume').addClass('hidden'); - $('#musicVolumeText').removeClass('hidden'); - }); - - $('#musicVolume').change(function() { - var newVolume = $('#musicVolume').val(); - newVolume = clamp(newVolume, 0, 100); - $('#adminMusic').prop('volume', newVolume / 100); - setCookie('musicVolume', newVolume, 365); - opts.updatedVolume = newVolume; - if(!opts.volumeUpdating) { - setTimeout(sendVolumeUpdate, opts.volumeUpdateDelay); - opts.volumeUpdating = true; - } - }); - - $('#toggleCombine').click(function(e) { - opts.messageCombining = !opts.messageCombining; - setCookie('messagecombining', (opts.messageCombining ? 'true' : 'false'), 365); - }); - - $('img.icon').error(iconError); - - - - - /***************************************** - * - * KICK EVERYTHING OFF - * - ******************************************/ - - runByond('?_src_=chat&proc=doneLoading'); - if ($('#loading').is(':visible')) { - $('#loading').remove(); - } - $('#userBar').show(); - opts.priorChatHeight = $(window).height(); -}); diff --git a/code/modules/tgui_panel/audio.dm b/code/modules/tgui_panel/audio.dm new file mode 100644 index 00000000000..68069615994 --- /dev/null +++ b/code/modules/tgui_panel/audio.dm @@ -0,0 +1,42 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/// Admin music volume, from 0 to 1. +/client/var/admin_music_volume = 1 + +/** + * public + * + * Sends music data to the browser. + * + * Optional settings: + * - pitch: the playback rate + * - start: the start time of the sound + * - end: when the musics stops playing + * + * required url string Must be an https URL. + * optional extra_data list Optional settings. + */ +/datum/tgui_panel/proc/play_music(url, extra_data) + if(!is_ready()) + return + if(!findtext(url, GLOB.is_http_protocol)) + return + var/list/payload = list() + if(length(extra_data) > 0) + for(var/key in extra_data) + payload[key] = extra_data[key] + payload["url"] = url + window.send_message("audio/playMusic", payload) + +/** + * public + * + * Stops playing music through the browser. + */ +/datum/tgui_panel/proc/stop_music() + if(!is_ready()) + return + window.send_message("audio/stopMusic") diff --git a/code/modules/tgui_panel/external.dm b/code/modules/tgui_panel/external.dm new file mode 100644 index 00000000000..9a9806be639 --- /dev/null +++ b/code/modules/tgui_panel/external.dm @@ -0,0 +1,37 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/client/var/datum/tgui_panel/tgui_panel + +/** + * tgui panel / chat troubleshooting verb + */ +/client/verb/fix_tgui_panel() + set name = "Fix chat" + set category = "OOC.Fix" + var/action + log_tgui(src, "Started fixing.", context = "verb/fix_tgui_panel") + + nuke_chat() + + // Failed to fix + action = alert(src, "Did that work?", "", "Yes", "No, switch to old ui") + if (action == "No, switch to old ui") + winset(src, "output", "on-show=&is-disabled=0&is-visible=1") + winset(src, "browseroutput", "is-disabled=1;is-visible=0") + log_tgui(src, "Failed to fix.", context = "verb/fix_tgui_panel") + +/client/proc/nuke_chat() + // Catch all solution (kick the whole thing in the pants) + winset(src, "output", "on-show=&is-disabled=0&is-visible=1") + winset(src, "browseroutput", "is-disabled=1;is-visible=0") + if(!tgui_panel || !istype(tgui_panel)) + log_tgui(src, "tgui_panel datum is missing", + context = "verb/fix_tgui_panel") + tgui_panel = new(src) + tgui_panel.initialize(force = TRUE) + // Force show the panel to see if there are any errors + winset(src, "output", "is-disabled=1&is-visible=0") + winset(src, "browseroutput", "is-disabled=0;is-visible=1") diff --git a/code/modules/tgui_panel/telemetry.dm b/code/modules/tgui_panel/telemetry.dm new file mode 100644 index 00000000000..e1abfb1e125 --- /dev/null +++ b/code/modules/tgui_panel/telemetry.dm @@ -0,0 +1,80 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/** + * Maximum number of connection records allowed to analyze. + * Should match the value set in the browser. + */ +#define TGUI_TELEMETRY_MAX_CONNECTIONS 5 + +/** + * Maximum time allocated for sending a telemetry packet. + */ +#define TGUI_TELEMETRY_RESPONSE_WINDOW 30 SECONDS + +/// Time of telemetry request +/datum/tgui_panel/var/telemetry_requested_at +/// Time of telemetry analysis completion +/datum/tgui_panel/var/telemetry_analyzed_at +/// List of previous client connections +/datum/tgui_panel/var/list/telemetry_connections + +/** + * private + * + * Requests some telemetry from the client. + */ +/datum/tgui_panel/proc/request_telemetry() + telemetry_requested_at = world.time + telemetry_analyzed_at = null + window.send_message("telemetry/request", list( + "limits" = list( + "connections" = TGUI_TELEMETRY_MAX_CONNECTIONS, + ), + )) + +/** + * private + * + * Analyzes a telemetry packet. + * + * Is currently only useful for detecting ban evasion attempts. + */ +/datum/tgui_panel/proc/analyze_telemetry(payload) + if(world.time > telemetry_requested_at + TGUI_TELEMETRY_RESPONSE_WINDOW) + message_admins("[key_name(client)] sent telemetry outside of the allocated time window.") + return + if(telemetry_analyzed_at) + message_admins("[key_name(client)] sent telemetry more than once.") + return + telemetry_analyzed_at = world.time + if(!payload) + return + telemetry_connections = payload["connections"] + var/len = length(telemetry_connections) + if(len == 0) + return + if(len > TGUI_TELEMETRY_MAX_CONNECTIONS) + message_admins("[key_name(client)] was kicked for sending a huge telemetry payload") + qdel(client) + return + var/list/found + for(var/i in 1 to len) + if(QDELETED(client)) + // He got cleaned up before we were done + return + var/list/row = telemetry_connections[i] + // Check for a malformed history object + if (!row || row.len < 3 || (!row["ckey"] || !row["address"] || !row["computer_id"])) + return + if (world.IsBanned(row["ckey"], row["address"], row["computer_id"], real_bans_only = TRUE)) + found = row + break + CHECK_TICK + // This fucker has a history of playing on a banned account. + if(found) + var/msg = "[key_name(client)] has a banned account in connection history! (Matched: [found["ckey"]], [found["address"]], [found["computer_id"]])" + message_admins(msg) + log_admin_private(msg) diff --git a/code/modules/tgui_panel/tgui_panel.dm b/code/modules/tgui_panel/tgui_panel.dm new file mode 100644 index 00000000000..b48010557e3 --- /dev/null +++ b/code/modules/tgui_panel/tgui_panel.dm @@ -0,0 +1,95 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/** + * tgui_panel datum + * Hosts tgchat and other nice features. + */ +/datum/tgui_panel + var/client/client + var/datum/tgui_window/window + var/broken = FALSE + var/initialized_at + +/datum/tgui_panel/New(client/client) + src.client = client + window = new(client, "browseroutput") + window.subscribe(src, .proc/on_message) + +/datum/tgui_panel/Del() + window.unsubscribe(src) + window.close() + return ..() + +/** + * public + * + * TRUE if panel is initialized and ready to receive messages. + */ +/datum/tgui_panel/proc/is_ready() + return !broken && window.is_ready() + +/** + * public + * + * Initializes tgui panel. + */ +/datum/tgui_panel/proc/initialize(force = FALSE) + initialized_at = world.time + // Perform a clean initialization + window.initialize(inline_assets = list( + get_asset_datum(/datum/asset/simple/tgui_common), + get_asset_datum(/datum/asset/simple/tgui_panel), + )) + window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome)) + window.send_asset(get_asset_datum(/datum/asset/spritesheet/chat)) + request_telemetry() + addtimer(CALLBACK(src, .proc/on_initialize_timed_out), 2 SECONDS) + +/** + * private + * + * Called when initialization has timed out. + */ +/datum/tgui_panel/proc/on_initialize_timed_out() + // Currently does nothing but sending a message to old chat. + SEND_TEXT(client, "Failed to load fancy chat, click HERE to attempt to reload it.") + +/** + * private + * + * Callback for handling incoming tgui messages. + */ +/datum/tgui_panel/proc/on_message(type, payload) + if(type == "ready") + broken = FALSE + window.send_message("update", list( + "config" = list( + "client" = list( + "ckey" = client.ckey, + "address" = client.address, + "computer_id" = client.computer_id, + ), + "window" = list( + "fancy" = FALSE, + "locked" = FALSE, + ), + ), + )) + return TRUE + if(type == "audio/setAdminMusicVolume") + client.admin_music_volume = payload["volume"] + return TRUE + if(type == "telemetry") + analyze_telemetry(payload) + return TRUE + +/** + * public + * + * Sends a round restart notification. + */ +/datum/tgui_panel/proc/send_roundrestart() + window.send_message("roundrestart") diff --git a/vanderlin.dme b/vanderlin.dme index 38c5fcbc58b..cc33c0dde61 100644 --- a/vanderlin.dme +++ b/vanderlin.dme @@ -462,6 +462,7 @@ #include "code\controllers\subsystem\soundloopers.dm" #include "code\controllers\subsystem\sounds.dm" #include "code\controllers\subsystem\spatial_grid.dm" +#include "code\controllers\subsystem\statpanel.dm" #include "code\controllers\subsystem\storyteller.dm" #include "code\controllers\subsystem\strategy_master.dm" #include "code\controllers\subsystem\tgui.dm" @@ -2690,7 +2691,6 @@ #include "code\modules\flufftext\Dreaming.dm" #include "code\modules\food_and_drinks\food.dm" #include "code\modules\food_and_drinks\food\snacks.dm" -#include "code\modules\goonchat\browserOutput.dm" #include "code\modules\holiday\holidays.dm" #include "code\modules\hydroponics\grown.dm" #include "code\modules\hydroponics\growninedible.dm" @@ -3666,6 +3666,10 @@ #include "code\modules\tgui\states\physical.dm" #include "code\modules\tgui\states\self.dm" #include "code\modules\tgui\states\zlevel.dm" +#include "code\modules\tgui_panel\audio.dm" +#include "code\modules\tgui_panel\external.dm" +#include "code\modules\tgui_panel\telemetry.dm" +#include "code\modules\tgui_panel\tgui_panel.dm" #include "code\modules\tooltip\tooltip.dm" #include "code\modules\underworld\underworld.dm" #include "code\modules\unit_tests\_unit_tests.dm" From ec4300d403c545aa00bcee7ee1c4613521877f52 Mon Sep 17 00:00:00 2001 From: forest2001 Date: Mon, 2 Feb 2026 20:46:45 +0000 Subject: [PATCH 02/67] . --- code/modules/client/verbs/ooc.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index d11e5f743d6..c3b75bd61fb 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -360,10 +360,12 @@ GLOBAL_LIST_INIT(oocpronouns_required, list( return else + chatOutput.start() var/action = alert(src, "Manually loading Chat, wait a bit and tell me if it's fixed", "", "Fixed", "Nope") if (action == "Fixed") log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by manually calling start()") else + chatOutput.load() alert(src, "How about now? (give it a moment (it may also try to load twice))", "", "Yes", "No") if (action == "Yes") log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by manually calling start() and forcing a load()") From 4e297686a30ec8f7ae19526fa4ffb2ad52995286 Mon Sep 17 00:00:00 2001 From: forest2001 Date: Mon, 2 Feb 2026 23:11:07 +0000 Subject: [PATCH 03/67] idfk --- code/__DEFINES/procpath.dm | 2 + code/__DEFINES/tgui.dm | 60 +- code/__HELPERS/_logging.dm | 34 +- code/controllers/subsystem/statpanel.dm | 23 +- code/modules/asset_cache/asset_cache_list.dm | 6 +- code/modules/asset_cache/asset_list.dm | 50 +- code/modules/goonchat/browserOutput.dm | 6 +- .../browserassets/html/statbrowser.html | 886 ++++++++++++++++++ code/modules/tgui_panel/tgui.dm | 81 ++ code/modules/tgui_panel/tgui_panel.dm | 37 +- code/modules/tgui_panel/tgui_window.dm | 429 +++++++++ vanderlin.dme | 3 + 12 files changed, 1585 insertions(+), 32 deletions(-) create mode 100644 code/modules/goonchat/browserassets/html/statbrowser.html create mode 100644 code/modules/tgui_panel/tgui.dm create mode 100644 code/modules/tgui_panel/tgui_window.dm diff --git a/code/__DEFINES/procpath.dm b/code/__DEFINES/procpath.dm index 11800583588..642ca3eab6c 100644 --- a/code/__DEFINES/procpath.dm +++ b/code/__DEFINES/procpath.dm @@ -22,3 +22,5 @@ var/category as text /// Only clients/mobs with `see_invisibility` higher can use the verb. var/invisibility as num + /// Whether or not the verb appears in statpanel and commandbar when you press space + var/hidden as num diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm index 1b3925f43a7..6d90079c035 100644 --- a/code/__DEFINES/tgui.dm +++ b/code/__DEFINES/tgui.dm @@ -1,4 +1,56 @@ -#define UI_INTERACTIVE 2 // Green/Interactive -#define UI_UPDATE 1 // Orange/Updates Only -#define UI_DISABLED 0 // Red/Disabled -#define UI_CLOSE -1 // Closed +/// Green eye; fully interactive +#define UI_INTERACTIVE 2 +/// Orange eye; updates but is not interactive +#define UI_UPDATE 1 +/// Red eye; disabled, does not update +#define UI_DISABLED 0 +/// UI Should close +#define UI_CLOSE -1 + +/// Maximum number of windows that can be suspended/reused +#define TGUI_WINDOW_SOFT_LIMIT 5 +/// Maximum number of open windows +#define TGUI_WINDOW_HARD_LIMIT 9 + +/// Maximum ping timeout allowed to detect zombie windows +#define TGUI_PING_TIMEOUT 4 SECONDS +/// Used for rate-limiting to prevent DoS by excessively refreshing a TGUI window +#define TGUI_REFRESH_FULL_UPDATE_COOLDOWN 2 SECONDS + +/// Window does not exist +#define TGUI_WINDOW_CLOSED 0 +/// Window was just opened, but is still not ready to be sent data +#define TGUI_WINDOW_LOADING 1 +/// Window is free and ready to receive data +#define TGUI_WINDOW_READY 2 + +/// Get a window id based on the provided pool index +#define TGUI_WINDOW_ID(index) "tgui-window-[index]" +/// Get a pool index of the provided window id +#define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13)) + +/// Creates a message packet for sending via output() +// This is {"type":type,"payload":payload}, but pre-encoded. This is much faster +// than doing it the normal way. +// To ensure this is correct, this is unit tested in tgui_create_message. +#define TGUI_CREATE_MESSAGE(type, payload) ( \ + "%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \ +) + +/// Creates a message packet for sending via output() specifically for opening tgsay using an embedded winget +// This is {"type":"open","payload":{"channel":channel,"mapfocus":[[map.focus]],"lobyfocus":[[lobby_browser.focus]]}}, but pre-encoded. +#define TGUI_CREATE_OPEN_MESSAGE(channel) ( \ + "%7b%22type%22%3a%22open%22%2c%22payload%22%3a%7b%22channel%22%3a%22[channel]%22%2c%22mapfocus%22%3a\[\[map.focus\]\]%2c%22lobbyfocus%22%3a\[\[lobby_browser.focus\]\]%7d%7d" \ +) + +/* +*Defines for the TGUI health analyser interface +*The higher the level, the more information you can see +*/ + +#define DETAIL_LEVEL_HEALTHANALYSER 0 +#define DETAIL_LEVEL_BODYSCAN 1 +#define DETAIL_LEVEL_FULL 2 + +#define UI_MODE_MINIMAL 1 +#define UI_MODE_CLASSIC 0 diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 483946163ba..bfb95e89d9d 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -216,9 +216,37 @@ WRITE_LOG(GLOB.hunted_log, text) /* ui logging */ - -/proc/log_tgui(text) - WRITE_LOG(GLOB.tgui_log, text) +/** + * Appends a tgui-related log entry. All arguments are optional. + */ +/proc/log_tgui(user, message, context, + datum/tgui_window/window, + datum/src_object) + var/entry = "" + // Insert user info + if(!user) + entry += "" + else if(istype(user, /mob)) + var/mob/mob = user + entry += "[mob.ckey] (as [mob] at [mob.x],[mob.y],[mob.z])" + else if(istype(user, /client)) + var/client/client = user + entry += "[client.ckey]" + // Insert context + if(context) + entry += " in [context]" + else if(window) + entry += " in [window.id]" + // Resolve src_object + if(!src_object && window?.locked_by) + src_object = window.locked_by.src_object + // Insert src_object info + if(src_object) + entry += "\nUsing: [src_object.type] [REF(src_object)]" + // Insert message + if(message) + entry += "\n[message]" + WRITE_LOG(GLOB.tgui_log, entry) /proc/log_storyteller(text, list/data) WRITE_LOG(GLOB.world_game_log, "STORYTELLERS: [text]") diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 84ac6828e44..6423185f7fd 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -16,7 +16,7 @@ SUBSYSTEM_DEF(statpanels) var/list/global_data = list( "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]", "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]", - "Round Time: [duration2text()]", + //"Round Time: [duration2text()]", "Map: [SSmapping.config?.map_name || "Loading..."]", ) @@ -31,15 +31,15 @@ SUBSYSTEM_DEF(statpanels) continue if(target.stat_tab == "Status") // var/ping_str = url_encode("Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)") - var/other_str = url_encode(json_encode(target.mob.get_status_tab_items())) + var/other_str = ""//url_encode(json_encode(target.mob.get_status_tab_items())) target << output("[encoded_global_data];null;[other_str]", "statbrowser:update") - if(!target.admin_holder) + if(!target.holder) target << output("", "statbrowser:remove_admin_tabs") else - if(!("Admin" in target.panel_tabs)) - target << output("[url_encode(target.admin_holder.href_token)]", "statbrowser:add_admin_tabs") - if(!("MC" in target.panel_tabs) && check_client_rights(target, R_DEBUG|R_HOST, FALSE)) - target << output("", "statbrowser:add_mc_tab") + //if(!("Admin" in target.panel_tabs)) + // target << output("[url_encode(target.holder.href_token)]", "statbrowser:add_admin_tabs") + //if(!("MC" in target.panel_tabs) && check_client_rights(target, R_DEBUG|R_HOST, FALSE)) + // target << output("", "statbrowser:add_mc_tab") if(target.stat_tab == "MC") var/turf/eye_turf = get_turf(target.eye) var/coord_entry = url_encode(COORD(eye_turf)) @@ -61,7 +61,7 @@ SUBSYSTEM_DEF(statpanels) if(!target_image.loc || target_image.loc.loc != target_mob.listed_turf || !target_image.override) continue overrides += target_image.loc - turfitems[++turfitems.len] = list("[target_mob.listed_turf]", REF(target_mob.listed_turf), htmlicon(target_mob.listed_turf, target, sourceonly=TRUE)) + turfitems[++turfitems.len] = list("[target_mob.listed_turf]", REF(target_mob.listed_turf))//, htmlicon(target_mob.listed_turf, target, sourceonly=TRUE)) for(var/tc in target_mob.listed_turf) var/atom/movable/turf_content = tc if(turf_content.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) @@ -77,9 +77,9 @@ SUBSYSTEM_DEF(statpanels) cached_images += REF(turf_content) turf_content.RegisterSignal(turf_content, COMSIG_PARENT_QDELETING, /atom/.proc/remove_from_cache) // we reset cache if anything in it gets deleted if(ismob(turf_content) || length(turf_content.overlays) > 2) - turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), costly_icon2html(turf_content, target, sourceonly=TRUE)) + turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), costly_icon2html(turf_content, target)) else - turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), icon2html(turf_content, target, sourceonly=TRUE)) + turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), icon2html(turf_content, target)) else turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content)) else @@ -142,3 +142,6 @@ SUBSYSTEM_DEF(statpanels) statbrowser_ready = TRUE init_verbs() + +/// Stat panel window declaration +/client/var/datum/tgui_window/stat_panel diff --git a/code/modules/asset_cache/asset_cache_list.dm b/code/modules/asset_cache/asset_cache_list.dm index 9fd378eb13d..92c06e17215 100644 --- a/code/modules/asset_cache/asset_cache_list.dm +++ b/code/modules/asset_cache/asset_cache_list.dm @@ -127,9 +127,9 @@ assets = list( "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', "errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js', - "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', - "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', - "browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', + //"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', + //"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', + //"browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', ) parents = list() diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index d02af334b3f..729bd920c0c 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -66,11 +66,18 @@ GLOBAL_LIST_EMPTY(asset_datums) fdel(asset_path) // just in case, sadly we can't use rust_g stuff here. fcopy(file_location, asset_path) -//If you don't need anything complicated. +/// If you don't need anything complicated. /datum/asset/simple _abstract = /datum/asset/simple - var/assets = list() //! list of assets for this datum in the form of asset_filename = asset_file. At runtime the asset_file will be converted into a asset_cache datum. - var/legacy = FALSE //! set to true to have this asset also be sent via browse_rsc when cdn asset transports are enabled. + /// list of assets for this datum in the form of: + /// asset_filename = asset_file. At runtime the asset_file will be + /// converted into a asset_cache datum. + var/assets = list() + /// Set to true to have this asset also be sent via the legacy browse_rsc + /// system when cdn transports are enabled? + var/legacy = FALSE + /// TRUE for keeping local asset names when browse_rsc backend is used + var/keep_local_name = FALSE /datum/asset/simple/register() for(var/asset_name in assets) @@ -94,6 +101,43 @@ GLOBAL_LIST_EMPTY(asset_datums) for (var/asset_name in assets) SSassets.transport.unregister_asset(asset_name) +// If you use a file(...) object, instead of caching the asset it will be loaded from disk every time it's requested. +// This is useful for development, but not recommended for production. +// And if TGS is defined, we're being run in a production environment. + +#ifdef TGS +/datum/asset/simple/tgui + keep_local_name = FALSE + assets = list( + "tgui.bundle.js" = "tgui/public/tgui.bundle.js", + "tgui.bundle.css" = "tgui/public/tgui.bundle.css", + ) + +/datum/asset/simple/tgui_panel + keep_local_name = FALSE + assets = list( + "tgui-panel.bundle.js" = "tgui/public/tgui-panel.bundle.js", + "tgui-panel.bundle.css" = "tgui/public/tgui-panel.bundle.css", + ) + +#else +/datum/asset/simple/tgui + keep_local_name = TRUE + assets = list( + "tgui.bundle.js" = file("tgui/public/tgui.bundle.js"), + "tgui.bundle.css" = file("tgui/public/tgui.bundle.css"), + ) + +/datum/asset/simple/tgui_panel + keep_local_name = TRUE + assets = list( + "tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"), + "tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"), + ) + +#endif + + // For registering or sending multiple others at once /datum/asset/group _abstract = /datum/asset/group diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 37d5d85877c..0a6a0e960e6 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -1,4 +1,4 @@ -/* + #define MAX_COOKIE_LENGTH 5 /********************************* @@ -231,6 +231,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico /datum/chatOutput/proc/debug(error) log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") +/* //Global chat procs /proc/to_chat_immediate(target, message, handle_whitespace = TRUE) if(!target || !message) @@ -290,7 +291,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico to_chat_immediate(target, message, handle_whitespace) return SSchat.queue(target, message, handle_whitespace) - +*/ /datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation) owner.force_white_theme() @@ -299,4 +300,3 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico #undef MAX_COOKIE_LENGTH -*/ diff --git a/code/modules/goonchat/browserassets/html/statbrowser.html b/code/modules/goonchat/browserassets/html/statbrowser.html new file mode 100644 index 00000000000..269d8aea691 --- /dev/null +++ b/code/modules/goonchat/browserassets/html/statbrowser.html @@ -0,0 +1,886 @@ + + + +Stat Browser + + + + + + + + +
+
+ + + \ No newline at end of file diff --git a/code/modules/tgui_panel/tgui.dm b/code/modules/tgui_panel/tgui.dm new file mode 100644 index 00000000000..f1369a1142f --- /dev/null +++ b/code/modules/tgui_panel/tgui.dm @@ -0,0 +1,81 @@ +/** + * private + * + * Updates the status, and returns TRUE if status has changed. + */ +/datum/tgui/proc/process_status() + var/prev_status = status + status = src_object.ui_status(user, state) + return prev_status != status + +/** + * private + * + * Callback for handling incoming tgui messages. + */ +/* +/datum/tgui/proc/on_message(type, list/payload, list/href_list) + // Pass act type messages to ui_act + if(type && copytext(type, 1, 5) == "act/") + var/act_type = copytext(type, 5) + + var/id = href_list["packetId"] + if(!isnull(id)) + id = text2num(id) + + var/total = text2num(href_list["totalPackets"]) + + if(total > MAX_MESSAGE_CHUNKS) + return + + if(id == 1) + partial_packets = new /list(total) + + partial_packets[id] = href_list["packet"] + + if(id != total) + return + + var/assembled_payload = "" + for(var/packet in partial_packets) + assembled_payload += packet + + payload = json_decode(assembled_payload) + partial_packets = null + + log_tgui(user, "Action: [act_type] [href_list["payload"]]", + window = window, + src_object = src_object) + process_status() + //DEFAULT_QUEUE_OR_CALL_VERB(VERB_CALLBACK(src, PROC_REF(on_act_message), act_type, payload, state)) + on_act_message(act_type, payload, state) + return FALSE + switch(type) + if("ready") + // Send a full update when the user manually refreshes the UI + if(initialized) + send_full_update() + initialized = TRUE + if("ping/reply") + initialized = TRUE + if("suspend") + close(can_be_suspended = TRUE) + if("close") + close(can_be_suspended = FALSE) + if("log") + if(href_list["fatal"]) + close(can_be_suspended = FALSE) + if("setSharedState") + if(status != UI_INTERACTIVE) + return + LAZYINITLIST(src_object.tgui_shared_states) + src_object.tgui_shared_states[href_list["key"]] = href_list["value"] + SStgui.update_uis(src_object) +*/ +/// Wrapper for behavior to potentially wait until the next tick if the server is overloaded +/datum/tgui/proc/on_act_message(act_type, payload, state) + if(QDELETED(src) || QDELETED(src_object)) + return + if(src_object.ui_act(act_type, payload, src, state)) + SStgui.update_uis(src_object) + diff --git a/code/modules/tgui_panel/tgui_panel.dm b/code/modules/tgui_panel/tgui_panel.dm index b48010557e3..784526578d4 100644 --- a/code/modules/tgui_panel/tgui_panel.dm +++ b/code/modules/tgui_panel/tgui_panel.dm @@ -39,12 +39,12 @@ /datum/tgui_panel/proc/initialize(force = FALSE) initialized_at = world.time // Perform a clean initialization - window.initialize(inline_assets = list( - get_asset_datum(/datum/asset/simple/tgui_common), - get_asset_datum(/datum/asset/simple/tgui_panel), - )) - window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome)) - window.send_asset(get_asset_datum(/datum/asset/spritesheet/chat)) +// window.initialize(inline_assets = list( +// get_asset_datum(/datum/asset/simple/tgui_common), +// get_asset_datum(/datum/asset/simple/tgui_panel), +// )) +// window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome)) +// window.send_asset(get_asset_datum(/datum/asset/spritesheet/chat)) request_telemetry() addtimer(CALLBACK(src, .proc/on_initialize_timed_out), 2 SECONDS) @@ -93,3 +93,28 @@ */ /datum/tgui_panel/proc/send_roundrestart() window.send_message("roundrestart") + +/** +* Compiles a full list of verbs to be sent to the browser +* Sends the 2D verbs vector of (verb category, verb name) +*/ +/client/proc/init_verbs() + if(IsAdminAdvancedProcCall()) + return + var/list/verblist = list() + var/list/verbstoprocess = verbs.Copy() + if(mob) + verbstoprocess += mob.verbs + for(var/atom/movable/thing as anything in mob.contents) + verbstoprocess += thing.verbs + panel_tabs.Cut() // panel_tabs get reset in init_verbs on JS side anyway + for(var/procpath/verb_to_init as anything in verbstoprocess) + if(!verb_to_init) + continue + if(verb_to_init.hidden) + continue + if(!istext(verb_to_init.category)) + continue + panel_tabs |= verb_to_init.category + verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name) + src.stat_panel.send_message("init_verbs", list(panel_tabs = panel_tabs, verblist = verblist)) diff --git a/code/modules/tgui_panel/tgui_window.dm b/code/modules/tgui_panel/tgui_window.dm new file mode 100644 index 00000000000..556f5872d08 --- /dev/null +++ b/code/modules/tgui_panel/tgui_window.dm @@ -0,0 +1,429 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/datum/tgui_window + var/id + var/client/client + var/pooled + var/pool_index + var/is_browser = FALSE + var/status = TGUI_WINDOW_CLOSED + var/locked = FALSE + var/datum/tgui/locked_by + var/datum/subscriber_object + var/subscriber_delegate + var/fatally_errored = FALSE + var/message_queue + var/sent_assets = list() + // Vars passed to initialize proc (and saved for later) + var/initial_strict_mode + var/initial_fancy + var/initial_assets + var/initial_inline_html + var/initial_inline_js + var/initial_inline_css + var/mouse_event_macro_set = FALSE + + /** + * Static list used to map in macros that will then emit execute events to the tgui window + * A small disclaimer though I'm no tech wiz: I don't think it's possible to map in right or middle + * clicks in the current state, as they're keywords rather than modifiers. + */ + var/static/list/byondToTguiEventMap = list( + "MouseDown" = "byond/mousedown", + "MouseUp" = "byond/mouseup", + "Ctrl" = "byond/ctrldown", + "Ctrl+UP" = "byond/ctrlup", + ) + +/** + * global + * + * Tracks open windows for a user. + */ +/client/var/list/tgui_windows = list() + + +/** + * public + * + * Create a new tgui window. + * + * required client /client + * required id string A unique window identifier. + */ +/datum/tgui_window/New(client/client, id, pooled = FALSE) + src.id = id + src.client = client + src.client.tgui_windows[id] = src + src.pooled = pooled + if(pooled) + src.pool_index = TGUI_WINDOW_INDEX(id) + +/** + * public + * + * Initializes the window with a fresh page. Puts window into the "loading" + * state. You can begin sending messages right after initializing. Messages + * will be put into the queue until the window finishes loading. + * + * optional strict_mode bool - Enables strict error handling and BSOD. + * optional fancy bool - If TRUE and if this is NOT a panel, will hide the window titlebar. + * optional assets list - List of assets to load during initialization. + * optional inline_html string - Custom HTML to inject. + * optional inline_js string - Custom JS to inject. + * optional inline_css string - Custom CSS to inject. + */ +/datum/tgui_window/proc/initialize( + strict_mode = FALSE, + fancy = FALSE, + assets = list(), + inline_html = "", + inline_js = "", + inline_css = "") + log_tgui(client, + context = "[id]/initialize", + window = src) + if(!client) + return + src.initial_fancy = fancy + src.initial_assets = assets + src.initial_inline_html = inline_html + src.initial_inline_js = inline_js + src.initial_inline_css = inline_css + status = TGUI_WINDOW_LOADING + fatally_errored = FALSE + // Build window options + var/options = "file=[id].html;can_minimize=0;auto_format=0;" + // Remove titlebar and resize handles for a fancy window + if(fancy) + options += "titlebar=0;can_resize=0;" + else + options += "titlebar=1;can_resize=1;" + // Generate page html + var/html = SStgui.basehtml + html = replacetextEx(html, "\[tgui:windowId]", id) + html = replacetextEx(html, "\[tgui:strictMode]", strict_mode) + // Inject assets + var/inline_assets_str = "" + for(var/datum/asset/asset in assets) + var/mappings = asset.get_url_mappings() + for(var/name in mappings) + var/url = mappings[name] + // Not encoding since asset strings are considered safe + if(copytext(name, -4) == ".css") + inline_assets_str += "Byond.loadCss('[url]', true);\n" + else if(copytext(name, -3) == ".js") + inline_assets_str += "Byond.loadJs('[url]', true);\n" + asset.send(client) + if(length(inline_assets_str)) + inline_assets_str = "\n" + html = replacetextEx(html, "\n", inline_assets_str) + // Inject inline HTML + if (inline_html) + html = replacetextEx(html, "", isfile(inline_html) ? file2text(inline_html) : inline_html) + // Inject inline JS + if (inline_js) + inline_js = "" + html = replacetextEx(html, "", inline_js) + // Inject inline CSS + if (inline_css) + inline_css = "" + html = replacetextEx(html, "", inline_css) + // Open the window + client << browse(html, "window=[id];[options]") + // Detect whether the control is a browser + is_browser = winexists(client, id) == "BROWSER" + // Instruct the client to signal UI when the window is closed. + if(!is_browser) + winset(client, id, "on-close=\"uiclose [id]\"") + +/** + * public + * + * Reinitializes the panel with previous data used for initialization. + */ +/datum/tgui_window/proc/reinitialize() + initialize( + strict_mode = initial_strict_mode, + fancy = initial_fancy, + assets = initial_assets, + inline_html = initial_inline_html, + inline_js = initial_inline_js, + inline_css = initial_inline_css) + // Resend assets + for(var/datum/asset/asset in sent_assets) + send_asset(asset) + +/** + * public + * + * Checks if the window is ready to receive data. + * + * return bool + */ +/datum/tgui_window/proc/is_ready() + return status == TGUI_WINDOW_READY + +/** + * public + * + * Checks if the window can be sanely suspended. + * + * return bool + */ +/datum/tgui_window/proc/can_be_suspended() + return !fatally_errored \ + && pooled \ + && pool_index > 0 \ + && pool_index <= TGUI_WINDOW_SOFT_LIMIT \ + && status == TGUI_WINDOW_READY + +/** + * public + * + * Acquire the window lock. Pool will not be able to provide this window + * to other UIs for the duration of the lock. + * + * Can be given an optional tgui datum, which will be automatically + * subscribed to incoming messages via the on_message proc. + * + * optional ui /datum/tgui + */ +/datum/tgui_window/proc/acquire_lock(datum/tgui/ui) + locked = TRUE + locked_by = ui + +/** + * public + * + * Release the window lock. + */ +/datum/tgui_window/proc/release_lock() + // Clean up assets sent by tgui datum which requested the lock + if(locked) + sent_assets = list() + locked = FALSE + locked_by = null + +/** + * public + * + * Subscribes the datum to consume window messages on a specified proc. + * + * Note, that this supports only one subscriber, because code for that + * is simpler and therefore faster. If necessary, this can be rewritten + * to support multiple subscribers. + */ +/datum/tgui_window/proc/subscribe(datum/object, delegate) + subscriber_object = object + subscriber_delegate = delegate + +/** + * public + * + * Unsubscribes the datum. Do not forget to call this when cleaning up. + */ +/datum/tgui_window/proc/unsubscribe(datum/object) + subscriber_object = null + subscriber_delegate = null + +/** + * public + * + * Close the UI. + * + * optional can_be_suspended bool + */ +/datum/tgui_window/proc/close(can_be_suspended = TRUE) + if(!client) + return + if(mouse_event_macro_set) + remove_mouse_macro() + if(can_be_suspended && can_be_suspended()) + log_tgui(client, + context = "[id]/close (suspending)", + window = src) + status = TGUI_WINDOW_READY + send_message("suspend") + return + log_tgui(client, + context = "[id]/close", + window = src) + release_lock() + status = TGUI_WINDOW_CLOSED + message_queue = null + // Do not close the window to give user some time + // to read the error message. + if(!fatally_errored) + client << browse(null, "window=[id]") + +/** + * public + * + * Sends a message to tgui window. + * + * required type string Message type + * required payload list Message payload + * optional force bool Send regardless of the ready status. + */ +/datum/tgui_window/proc/send_message(type, payload, force) + if(!client) + return + var/message = TGUI_CREATE_MESSAGE(type, payload) + // Place into queue if window is still loading + if(!force && status != TGUI_WINDOW_READY) + if(!message_queue) + message_queue = list() + message_queue += list(message) + return + client << output(message, is_browser \ + ? "[id]:update" \ + : "[id].browser:update") + +/** + * public + * + * Sends a raw payload to tgui window. + * + * required message string JSON+urlencoded blob to send. + * optional force bool Send regardless of the ready status. + */ +/datum/tgui_window/proc/send_raw_message(message, force) + if(!client) + return + // Place into queue if window is still loading + if(!force && status != TGUI_WINDOW_READY) + if(!message_queue) + message_queue = list() + message_queue += list(message) + return + client << output(message, is_browser \ + ? "[id]:update" \ + : "[id].browser:update") + +/** + * public + * + * Makes an asset available to use in tgui. + * + * required asset datum/asset + * + * return bool - TRUE if any assets had to be sent to the client + */ +/datum/tgui_window/proc/send_asset(datum/asset/asset) + if(!client || !asset) + return + sent_assets |= list(asset) + . = asset.send(client) + if(istype(asset, /datum/asset/spritesheet)) + var/datum/asset/spritesheet/spritesheet = asset + send_message("asset/stylesheet", spritesheet.css_filename()) + //send_raw_message(asset.get_serialized_url_mappings()) + +/** + * private + * + * Sends queued messages if the queue wasn't empty. + */ +/datum/tgui_window/proc/flush_message_queue() + if(!client || !message_queue) + return + for(var/message in message_queue) + client << output(message, is_browser \ + ? "[id]:update" \ + : "[id].browser:update") + message_queue = null + +/** + * public + * + * Replaces the inline HTML content. + * + * required inline_html string HTML to inject + */ +/datum/tgui_window/proc/replace_html(inline_html = "") + client << output(url_encode(inline_html), is_browser \ + ? "[id]:replaceHtml" \ + : "[id].browser:replaceHtml") + +/** + * private + * + * Callback for handling incoming tgui messages. + */ +/datum/tgui_window/proc/on_message(type, payload, href_list) + // Status can be READY if user has refreshed the window. + if(type == "ready" && status == TGUI_WINDOW_READY) + // Resend the assets + for(var/asset in sent_assets) + send_asset(asset) + // Mark this window as fatally errored which prevents it from + // being suspended. + if(type == "log" && href_list["fatal"]) + fatally_errored = TRUE + // Mark window as ready since we received this message from somewhere + if(status != TGUI_WINDOW_READY) + status = TGUI_WINDOW_READY + flush_message_queue() + // Pass message to UI that requested the lock + //if(locked && locked_by) + // var/prevent_default = locked_by.on_message(type, payload, href_list) + // if(prevent_default) + // return + // Pass message to the subscriber + else if(subscriber_object) + var/prevent_default = call( + subscriber_object, + subscriber_delegate)(type, payload, href_list) + if(prevent_default) + return + // If not locked, handle these message types + switch(type) + if("ping") + send_message("ping/reply", payload) + if("suspend") + close(can_be_suspended = TRUE) + if("close") + close(can_be_suspended = FALSE) + if("openLink") + client << link(href_list["url"]) + if("cacheReloaded") + reinitialize() + //if("chat/resend") + // SSchat.handle_resend(client, payload) + +/* +/datum/tgui_window/vv_edit_var(var_name, var_value) + return var_name != NAMEOF(src, id) && ..() +*/ + +/datum/tgui_window/proc/set_mouse_macro() + if(mouse_event_macro_set) + return + + for(var/mouseMacro in byondToTguiEventMap) + var/command_template = ".output CONTROL PAYLOAD" + var/event_message = TGUI_CREATE_MESSAGE(byondToTguiEventMap[mouseMacro], null) + var target_control = is_browser \ + ? "[id]:update" \ + : "[id].browser:update" + var/with_id = replacetext(command_template, "CONTROL", target_control) + var/full_command = replacetext(with_id, "PAYLOAD", event_message) + + var/list/params = list() + params["parent"] = "default" //Technically this is external to tgui but whatever + params["name"] = mouseMacro + params["command"] = full_command + + winset(client, "[mouseMacro]Window[id]Macro", params) + mouse_event_macro_set = TRUE + +/datum/tgui_window/proc/remove_mouse_macro() + if(!mouse_event_macro_set) + stack_trace("Unsetting mouse macro on tgui window that has none") + for(var/mouseMacro in byondToTguiEventMap) + winset(client, null, "[mouseMacro]Window[id]Macro.parent=null") + mouse_event_macro_set = FALSE diff --git a/vanderlin.dme b/vanderlin.dme index cc33c0dde61..6f24745c35d 100644 --- a/vanderlin.dme +++ b/vanderlin.dme @@ -2691,6 +2691,7 @@ #include "code\modules\flufftext\Dreaming.dm" #include "code\modules\food_and_drinks\food.dm" #include "code\modules\food_and_drinks\food\snacks.dm" +#include "code\modules\goonchat\browserOutput.dm" #include "code\modules\holiday\holidays.dm" #include "code\modules\hydroponics\grown.dm" #include "code\modules\hydroponics\growninedible.dm" @@ -3669,7 +3670,9 @@ #include "code\modules\tgui_panel\audio.dm" #include "code\modules\tgui_panel\external.dm" #include "code\modules\tgui_panel\telemetry.dm" +#include "code\modules\tgui_panel\tgui.dm" #include "code\modules\tgui_panel\tgui_panel.dm" +#include "code\modules\tgui_panel\tgui_window.dm" #include "code\modules\tooltip\tooltip.dm" #include "code\modules\underworld\underworld.dm" #include "code\modules\unit_tests\_unit_tests.dm" From 422fbb80ad958703bc52c5288137cba2c2ed5444 Mon Sep 17 00:00:00 2001 From: CheffieGithub <113442598+CheffieGithub@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:17:35 +0000 Subject: [PATCH 04/67] effective copypasting --- code/__DEFINES/dcs/signals/signals_datum.dm | 7 + code/__DEFINES/dcs/signals/signals_tgui.dm | 2 + code/__DEFINES/interaction_flags.dm | 4 + code/__DEFINES/tgui.dm | 38 +- code/__DEFINES/traits.dm | 3 + .../configuration/entries/general.dm | 7 + code/controllers/subsystem/chat.dm | 2 - code/controllers/subsystem/tgui.dm | 359 +++++++++++- code/datums/datum.dm | 4 + code/modules/asset_cache/asset_cache_list.dm | 8 +- code/modules/asset_cache/asset_list.dm | 13 + .../asset_cache/assets/icon_ref_map.dm | 28 + .../spritesheet/legacy/legacy_spritesheet.dm | 2 + code/modules/client/client_procs.dm | 22 + code/modules/emoji/emoji_parse.dm | 2 +- code/modules/tgui/external.dm | 219 +++++-- code/modules/tgui/states.dm | 81 ++- code/modules/tgui/states/default.dm | 21 +- code/modules/tgui/subsystem.dm | 259 --------- code/modules/tgui/tgui.dm | 534 +++++++++--------- .../{tgui_panel => tgui}/tgui_window.dm | 108 ++-- code/modules/tgui_panel/tgui.dm | 81 --- code/modules/tgui_panel/tgui_panel.dm | 64 +-- vanderlin.dme | 7 +- 24 files changed, 1022 insertions(+), 853 deletions(-) create mode 100644 code/__DEFINES/dcs/signals/signals_datum.dm create mode 100644 code/__DEFINES/dcs/signals/signals_tgui.dm create mode 100644 code/modules/asset_cache/assets/icon_ref_map.dm delete mode 100644 code/modules/tgui/subsystem.dm rename code/modules/{tgui_panel => tgui}/tgui_window.dm (80%) delete mode 100644 code/modules/tgui_panel/tgui.dm diff --git a/code/__DEFINES/dcs/signals/signals_datum.dm b/code/__DEFINES/dcs/signals/signals_datum.dm new file mode 100644 index 00000000000..0a0256b6ba4 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_datum.dm @@ -0,0 +1,7 @@ +// Datum signals. Format: +// When the signal is called: (signal arguments) +// All signals send the source datum of the signal as the first argument + +// /datum signals +/// from datum ui_act (usr, action) +#define COMSIG_UI_ACT "COMSIG_UI_ACT" diff --git a/code/__DEFINES/dcs/signals/signals_tgui.dm b/code/__DEFINES/dcs/signals/signals_tgui.dm new file mode 100644 index 00000000000..67b979be780 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_tgui.dm @@ -0,0 +1,2 @@ +/// Window is fully visible and we can make fragile calls +#define COMSIG_TGUI_WINDOW_VISIBLE "tgui_window_visible" diff --git a/code/__DEFINES/interaction_flags.dm b/code/__DEFINES/interaction_flags.dm index 0008e863c5d..45921e6b93d 100644 --- a/code/__DEFINES/interaction_flags.dm +++ b/code/__DEFINES/interaction_flags.dm @@ -16,6 +16,10 @@ #define INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND (1<<7) /// adds hiddenprints instead of fingerprints on interact #define INTERACT_ATOM_NO_FINGERPRINT_INTERACT (1<<8) +/// allows this atom to skip the adjacency check +#define INTERACT_ATOM_ALLOW_USER_LOCATION (1<<9) +/// ignores mobility check +#define INTERACT_ATOM_IGNORE_MOBILITY (1<<10) /// attempt pickup on attack_hand for items #define INTERACT_ITEM_ATTACK_HAND_PICKUP (1<<0) diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm index 6d90079c035..ca90b2940d6 100644 --- a/code/__DEFINES/tgui.dm +++ b/code/__DEFINES/tgui.dm @@ -13,9 +13,9 @@ #define TGUI_WINDOW_HARD_LIMIT 9 /// Maximum ping timeout allowed to detect zombie windows -#define TGUI_PING_TIMEOUT 4 SECONDS +#define TGUI_PING_TIMEOUT (4 SECONDS) /// Used for rate-limiting to prevent DoS by excessively refreshing a TGUI window -#define TGUI_REFRESH_FULL_UPDATE_COOLDOWN 2 SECONDS +#define TGUI_REFRESH_FULL_UPDATE_COOLDOWN (1 SECONDS) /// Window does not exist #define TGUI_WINDOW_CLOSED 0 @@ -24,6 +24,16 @@ /// Window is free and ready to receive data #define TGUI_WINDOW_READY 2 +/// Though not the maximum renderable ByondUis within tgui, this is the maximum that the server will manage per-UI +#define TGUI_MANAGED_BYONDUI_LIMIT 10 + +// These are defines instead of being inline, as they're being sent over +// from tgui-core, so can't be easily played with +#define TGUI_MANAGED_BYONDUI_TYPE_RENDER "renderByondUi" +#define TGUI_MANAGED_BYONDUI_TYPE_UNMOUNT "unmountByondUi" + +#define TGUI_MANAGED_BYONDUI_PAYLOAD_ID "renderByondUi" + /// Get a window id based on the provided pool index #define TGUI_WINDOW_ID(index) "tgui-window-[index]" /// Get a pool index of the provided window id @@ -37,20 +47,10 @@ "%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \ ) -/// Creates a message packet for sending via output() specifically for opening tgsay using an embedded winget -// This is {"type":"open","payload":{"channel":channel,"mapfocus":[[map.focus]],"lobyfocus":[[lobby_browser.focus]]}}, but pre-encoded. -#define TGUI_CREATE_OPEN_MESSAGE(channel) ( \ - "%7b%22type%22%3a%22open%22%2c%22payload%22%3a%7b%22channel%22%3a%22[channel]%22%2c%22mapfocus%22%3a\[\[map.focus\]\]%2c%22lobbyfocus%22%3a\[\[lobby_browser.focus\]\]%7d%7d" \ -) - -/* -*Defines for the TGUI health analyser interface -*The higher the level, the more information you can see -*/ - -#define DETAIL_LEVEL_HEALTHANALYSER 0 -#define DETAIL_LEVEL_BODYSCAN 1 -#define DETAIL_LEVEL_FULL 2 - -#define UI_MODE_MINIMAL 1 -#define UI_MODE_CLASSIC 0 +/** + * Gets a ui_state that checks to see if the user has specific admin permissions. + * + * Arguments: + * * required_perms: Which admin permission flags to check the user for, such as [R_ADMIN] + */ +#define ADMIN_STATE(required_perms) (GLOB.admin_states[required_perms] ||= new /datum/ui_state/admin_state(required_perms)) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index da4c83bc551..d53acf3ed65 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -615,3 +615,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Turf trait for when a turf is transparent #define TURF_Z_TRANSPARENT_TRAIT "turf_z_transparent" + +/// This mob should never close UI even if it doesn't have a client +#define TRAIT_PRESERVE_UI_WITHOUT_CLIENT "preserve_ui_without_client" diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index f9f1bb0b271..3efddbba728 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -516,3 +516,10 @@ //Endpoint for Github Issues, the `owner/repo` part. /datum/config_entry/string/issue_slug protection = CONFIG_ENTRY_LOCKED + +/** + * Tgui ui_act payloads larger than 2kb are split into chunks a maximum of 1kb in size. + * This flag represents the maximum chunk count the server is willing to receive. + */ +/datum/config_entry/number/tgui_max_chunk_count + default = 32 diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index 4127aaffe0e..bda4fb57d9b 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -7,7 +7,6 @@ SUBSYSTEM_DEF(chat) var/list/payload = list() - /datum/controller/subsystem/chat/fire() for(var/client/C as anything in payload) C << output(payload[C], "browseroutput:output") @@ -16,7 +15,6 @@ SUBSYSTEM_DEF(chat) if(MC_TICK_CHECK) return - /datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE) if(!target || !message) return diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm index c687a3b20e0..26159a1cdf1 100644 --- a/code/controllers/subsystem/tgui.dm +++ b/code/controllers/subsystem/tgui.dm @@ -1,3 +1,15 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/** + * tgui subsystem + * + * Contains all tgui state and subsystem code. + * + */ + SUBSYSTEM_DEF(tgui) name = "tgui" wait = 9 @@ -5,32 +17,339 @@ SUBSYSTEM_DEF(tgui) priority = FIRE_PRIORITY_TGUI runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - var/list/currentrun = list() - var/list/open_uis = list() // A list of open UIs, grouped by src_object and ui_key. - var/list/processing_uis = list() // A list of processing UIs, ungrouped. - var/basehtml // The HTML base used for all UIs. + /// A list of UIs scheduled to process + var/list/current_run = list() + /// A list of all open UIs + var/list/all_uis = list() + /// The HTML base used for all UIs. + var/basehtml /datum/controller/subsystem/tgui/PreInit() - basehtml = file2text('tgui-next/packages/tgui/public/tgui-main.html') + basehtml = file2text('tgui/public/tgui.html') + + // Inject inline helper functions + var/helpers = file2text('tgui/public/helpers.min.js') + helpers = "" + basehtml = replacetextEx(basehtml, "", helpers) + + // // Inject inline ntos-error styles + // var/ntos_error = file2text('tgui/public/ntos-error.min.css') + // ntos_error = "" + // basehtml = replacetextEx(basehtml, "", ntos_error) + + // basehtml = replacetextEx(basehtml, "", "Nanotrasen (c) 2525-[CURRENT_STATION_YEAR]") + /datum/controller/subsystem/tgui/Shutdown() close_all_uis() -/datum/controller/subsystem/tgui/stat_entry() - ..("P:[processing_uis.len]") +/datum/controller/subsystem/tgui/stat_entry(msg) + msg = "P:[length(all_uis)]" + return ..() -/datum/controller/subsystem/tgui/fire(resumed = 0) - if (!resumed) - src.currentrun = processing_uis.Copy() - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - - while(currentrun.len) - var/datum/tgui/ui = currentrun[currentrun.len] - currentrun.len-- - if(ui && ui.user && ui.src_object) - ui.process() +/datum/controller/subsystem/tgui/fire(resumed = FALSE) + if(!resumed) + src.current_run = all_uis.Copy() + // Cache for sanic speed (lists are references anyways) + var/list/current_run = src.current_run + while(length(current_run)) + var/datum/tgui/ui = current_run[length(current_run)] + current_run.len-- + // TODO: Move user/src_object check to process() + if(ui?.user && ui.src_object) + ui.process(wait * 0.1) else - processing_uis.Remove(ui) - if (MC_TICK_CHECK) + ui.close(0) + if(MC_TICK_CHECK) return + +/** + * public + * + * Requests a usable tgui window from the pool. + * Returns null if pool was exhausted. + * + * required user mob + * return datum/tgui_window + */ +/datum/controller/subsystem/tgui/proc/request_pooled_window(mob/user) + if(!user.client) + return null + var/list/windows = user.client.tgui_windows + var/window_id + var/datum/tgui_window/window + var/window_found = FALSE + // Find a usable window + for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT) + window_id = TGUI_WINDOW_ID(i) + window = windows[window_id] + // As we are looping, create missing window datums + if(!window) + window = new(user.client, window_id, pooled = TRUE) + // Skip windows with acquired locks + if(window.locked) + continue + if(window.status == TGUI_WINDOW_READY) + return window + if(window.status == TGUI_WINDOW_CLOSED) + window.status = TGUI_WINDOW_LOADING + window_found = TRUE + break + if(!window_found) + log_tgui(user, "Error: Pool exhausted", + context = "SStgui/request_pooled_window") + return null + return window + +/** + * public + * + * Force closes all tgui windows. + * + * required user mob + */ +/datum/controller/subsystem/tgui/proc/force_close_all_windows(mob/user) + log_tgui(user, context = "SStgui/force_close_all_windows") + if(user.client) + user.client.tgui_windows = list() + for(var/i in 1 to TGUI_WINDOW_HARD_LIMIT) + var/window_id = TGUI_WINDOW_ID(i) + user << browse(null, "window=[window_id]") + +/** + * public + * + * Force closes the tgui window by window_id. + * + * required user mob + * required window_id string + */ +/datum/controller/subsystem/tgui/proc/force_close_window(mob/user, window_id) + log_tgui(user, context = "SStgui/force_close_window") + // Close all tgui datums based on window_id. + for(var/datum/tgui/ui in user.tgui_open_uis) + if(ui.window && ui.window.id == window_id) + ui.close(can_be_suspended = FALSE) + // Close window directly just to be sure. + user << browse(null, "window=[window_id]") + +/** + * public + * + * Try to find an instance of a UI, and push an update to it. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object/datum which owns the UI. + * optional ui datum/tgui The UI to be updated, if it exists. + * optional force_open bool If the UI should be re-opened instead of updated. + * + * return datum/tgui The found UI. + */ +/datum/controller/subsystem/tgui/proc/try_update_ui( + mob/user, + datum/src_object, + datum/tgui/ui) + // Look up a UI if it wasn't passed + if(isnull(ui)) + ui = get_open_ui(user, src_object) + // Couldn't find a UI. + if(isnull(ui)) + return null + ui.process_status() + // UI ended up with the closed status + // or is actively trying to close itself. + // FIXME: Doesn't actually fix the paper bug. + if(ui.status <= UI_CLOSE) + ui.close() + return null + ui.send_update() + return ui + +/** + * public + * + * Get a open UI given a user and src_object. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object/datum which owns the UI. + * + * return datum/tgui The found UI. + */ +/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object) + // No UIs opened for this src_object + if(!LAZYLEN(src_object?.open_uis)) + return null + for(var/datum/tgui/ui in src_object.open_uis) + // Make sure we have the right user + if(ui.user == user) + return ui + return null + +/** + * public + * + * Update all UIs attached to src_object. + * + * required src_object datum The object/datum which owns the UIs. + * + * return int The number of UIs updated. + */ +/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object) + // No UIs opened for this src_object + if(!LAZYLEN(src_object?.open_uis)) + return 0 + var/count = 0 + for(var/datum/tgui/ui in src_object.open_uis) + // Check if UI is valid. + if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user)) + INVOKE_ASYNC(ui, TYPE_PROC_REF(/datum/tgui, process), wait * 0.1, TRUE) + count++ + return count + +/** + * public + * + * Close all UIs attached to src_object. + * + * required src_object datum The object/datum which owns the UIs. + * + * return int The number of UIs closed. + */ +/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object) + // No UIs opened for this src_object + if(!LAZYLEN(src_object?.open_uis)) + return 0 + var/count = 0 + for(var/datum/tgui/ui in src_object.open_uis) + // Check if UI is valid. + if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user)) + ui.close() + count++ + return count + +/** + * public + * + * Close all UIs regardless of their attachment to src_object. + * + * return int The number of UIs closed. + */ +/datum/controller/subsystem/tgui/proc/close_all_uis() + var/count = 0 + for(var/datum/tgui/ui in all_uis) + // Check if UI is valid. + if(ui?.src_object && ui.user && ui.src_object.ui_host(ui.user)) + ui.close() + count++ + return count + +/** + * public + * + * Update all UIs belonging to a user. + * + * required user mob The mob who opened/is using the UI. + * optional src_object datum If provided, only update UIs belonging this src_object. + * + * return int The number of UIs updated. + */ +/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object) + var/count = 0 + if(!length(user?.tgui_open_uis)) + return count + + for(var/datum/tgui/ui in user.tgui_open_uis) + if(isnull(src_object) || ui.src_object == src_object) + ui.process(wait * 0.1, force = TRUE) + count++ + + return count + +/** + * public + * + * Close all UIs belonging to a user. + * + * required user mob The mob who opened/is using the UI. + * optional src_object datum If provided, only close UIs belonging this src_object. + * + * return int The number of UIs closed. + */ +/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object) + var/count = 0 + if(length(user?.tgui_open_uis) == 0) + return count + for(var/datum/tgui/ui in user.tgui_open_uis) + if(isnull(src_object) || ui.src_object == src_object) + ui.close() + count++ + return count + +/** + * private + * + * Add a UI to the list of open UIs. + * + * required ui datum/tgui The UI to be added. + */ +/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui) + ui.user?.tgui_open_uis |= ui + LAZYOR(ui.src_object.open_uis, ui) + all_uis |= ui + +/** + * private + * + * Remove a UI from the list of open UIs. + * + * required ui datum/tgui The UI to be removed. + * + * return bool If the UI was removed or not. + */ +/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui) + // Remove it from the list of processing UIs. + all_uis -= ui + current_run -= ui + // If the user exists, remove it from them too. + if(ui.user) + ui.user.tgui_open_uis -= ui + if(ui.src_object) + LAZYREMOVE(ui.src_object.open_uis, ui) + return TRUE + +/** + * private + * + * Handle client logout, by closing all their UIs. + * + * required user mob The mob which logged out. + * + * return int The number of UIs closed. + */ +/datum/controller/subsystem/tgui/proc/on_logout(mob/user) + close_user_uis(user) + +/** + * private + * + * Handle clients switching mobs, by transferring their UIs. + * + * required user source The client's original mob. + * required user target The client's new mob. + * + * return bool If the UIs were transferred. + */ +/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target) + // The old mob had no open UIs. + if(length(source?.tgui_open_uis) == 0) + return FALSE + if(isnull(target.tgui_open_uis) || !istype(target.tgui_open_uis, /list)) + target.tgui_open_uis = list() + // Transfer all the UIs. + for(var/datum/tgui/ui in source.tgui_open_uis) + // Inform the UIs of their new owner. + ui.user = target + target.tgui_open_uis += ui + // Clear the old list. + source.tgui_open_uis.Cut() + return TRUE diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 622f941ae1e..7fc23c15cfc 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -17,6 +17,10 @@ */ var/gc_destroyed + /// Open uis owned by this datum + /// Lazy, since this case is semi rare + var/list/open_uis + /// Active timers with this datum as the target var/list/active_timers /// Status traits attached to this datum diff --git a/code/modules/asset_cache/asset_cache_list.dm b/code/modules/asset_cache/asset_cache_list.dm index 92c06e17215..1ad73a6e50d 100644 --- a/code/modules/asset_cache/asset_cache_list.dm +++ b/code/modules/asset_cache/asset_cache_list.dm @@ -85,10 +85,10 @@ /datum/asset/simple/notes -/datum/asset/spritesheet_batched/goonchat +/datum/asset/spritesheet_batched/chat name = "chat" -/datum/asset/spritesheet_batched/goonchat/create_spritesheets() +/datum/asset/spritesheet_batched/chat/create_spritesheets() // pre-loading all lanugage icons also helps to avoid meta insert_all_icons("language", 'icons/language.dmi') // catch languages which are pulling icons from another file @@ -98,14 +98,12 @@ var/icon_state = initial(L.icon_state) insert_icon("language-[icon_state]", uni_icon(icon, icon_state)) -/datum/asset/group/tgui - /datum/asset/group/goonchat children = list( /datum/asset/simple/jquery, /datum/asset/simple/purify, /datum/asset/simple/namespaced/goonchat, - /datum/asset/spritesheet_batched/goonchat, + /datum/asset/spritesheet_batched/chat, /datum/asset/simple/namespaced/fontawesome, /datum/asset/simple/namespaced/roguefonts ) diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index 2294fcbd539..cbf9c19a99a 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -16,6 +16,9 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset abstract_type = /datum/asset + var/cached_serialized_url_mappings + var/cached_serialized_url_mappings_transport_type + /// Whether or not this asset should be loaded in the "early assets" SS var/early = FALSE @@ -40,6 +43,14 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/proc/get_url_mappings() return list() +/// Returns a cached tgui message of URL mappings +/datum/asset/proc/get_serialized_url_mappings() + if(isnull(cached_serialized_url_mappings) || cached_serialized_url_mappings_transport_type != SSassets.transport.type) + cached_serialized_url_mappings = TGUI_CREATE_MESSAGE("asset/mappings", get_url_mappings()) + cached_serialized_url_mappings_transport_type = SSassets.transport.type + + return cached_serialized_url_mappings + /datum/asset/proc/register() return @@ -53,6 +64,8 @@ GLOBAL_LIST_EMPTY(asset_datums) /// Immediately regenerate the asset, overwriting any cache. /datum/asset/proc/regenerate() unregister() + cached_serialized_url_mappings = null + cached_serialized_url_mappings_transport_type = null register() /// Unregisters any assets from the transport. diff --git a/code/modules/asset_cache/assets/icon_ref_map.dm b/code/modules/asset_cache/assets/icon_ref_map.dm new file mode 100644 index 00000000000..4de1a44fab0 --- /dev/null +++ b/code/modules/asset_cache/assets/icon_ref_map.dm @@ -0,0 +1,28 @@ +/// Maps icon names to ref values +/datum/asset/json/icon_ref_map + name = "icon_ref_map" + early = TRUE + +/datum/asset/json/icon_ref_map/generate() + var/list/data = list() //"icons/obj/drinks.dmi" => "[0xc000020]" + + //var/start = "0xc000000" + var/value = 0 + + while(TRUE) + value += 1 + var/ref = "\[0xc[num2text(value,6,16)]\]" + var/mystery_meat = locate(ref) + + if(isicon(mystery_meat)) + if(!isfile(mystery_meat)) // Ignore the runtime icons for now + continue + var/path = get_icon_dmi_path(mystery_meat) //Try to get the icon path + if(path) + data[path] = ref + else if(mystery_meat) + continue //Some other non-icon resource, ogg/json/whatever + else //Out of resources end this, could also try to end this earlier as soon as runtime generated icons appear but eh + break + + return data diff --git a/code/modules/asset_cache/spritesheet/legacy/legacy_spritesheet.dm b/code/modules/asset_cache/spritesheet/legacy/legacy_spritesheet.dm index ee68aa2d332..3951bd25c5e 100644 --- a/code/modules/asset_cache/spritesheet/legacy/legacy_spritesheet.dm +++ b/code/modules/asset_cache/spritesheet/legacy/legacy_spritesheet.dm @@ -64,6 +64,8 @@ fdel("data/spritesheets/[name]_[size_id].png") sizes = list() to_generate = list() + cached_serialized_url_mappings = null + cached_serialized_url_mappings_transport_type = null fully_generated = FALSE var/old_load = load_immediately load_immediately = TRUE diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index c0f10cbd002..cd0390e1d18 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -1401,6 +1401,28 @@ GLOBAL_LIST_EMPTY(respawncounts) return TRUE return FALSE +/// compiles a full list of verbs and sends it to the browser +/client/proc/init_verbs() + if(IsAdminAdvancedProcCall()) + return + var/list/verblist = list() + var/list/verbstoprocess = verbs.Copy() + if(mob) + verbstoprocess += mob.verbs + for(var/atom/movable/thing as anything in mob.contents) + verbstoprocess += thing.verbs + panel_tabs.Cut() // panel_tabs get reset in init_verbs on JS side anyway + for(var/procpath/verb_to_init as anything in verbstoprocess) + if(!verb_to_init) + continue + if(verb_to_init.hidden) + continue + if(!istext(verb_to_init.category)) + continue + panel_tabs |= verb_to_init.category + verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name) + src.stat_panel.send_message("init_verbs", list(panel_tabs = panel_tabs, verblist = verblist)) + #undef LIMITER_SIZE #undef CURRENT_SECOND #undef SECOND_COUNT diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm index b15842ab2bd..0bb7f150b24 100644 --- a/code/modules/emoji/emoji_parse.dm +++ b/code/modules/emoji/emoji_parse.dm @@ -15,7 +15,7 @@ search = findtext(text, ":", pos+1) if(search) emoji = lowertext(copytext(text, pos+1, search)) -// var/datum/asset/spritesheet_batched/sheet = get_asset_datum(/datum/asset/spritesheet_batched/goonchat) +// var/datum/asset/spritesheet_batched/sheet = get_asset_datum(/datum/asset/spritesheet_batched/chat) var/datum/asset/spritesheet_batched/sheet var/tag = sheet.icon_tag("emoji-[emoji]") if(tag) diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm index 83b28553ea2..daee4740d6a 100644 --- a/code/modules/tgui/external.dm +++ b/code/modules/tgui/external.dm @@ -1,8 +1,9 @@ -/** - * tgui external +/*! + * External tgui definitions, such as src_object APIs. * - * Contains all external tgui declarations. - **/ + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ /** * public @@ -11,13 +12,9 @@ * If this proc is not implemented properly, the UI will not update correctly. * * required user mob The mob who opened/is using the UI. - * optional ui_key string The ui_key of the UI. * optional ui datum/tgui The UI to be updated, if it exists. - * optional force_open bool If the UI should be re-opened instead of updated. - * optional master_ui datum/tgui The parent UI. - * optional state datum/ui_state The state used to determine status. - **/ -/datum/proc/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + */ +/datum/proc/ui_interact(mob/user, datum/tgui/ui) return FALSE // Not implemented. /** @@ -29,7 +26,7 @@ * required user mob The mob interacting with the UI. * * return list Data to be sent to the UI. - **/ + */ /datum/proc/ui_data(mob/user) return list() // Not implemented. @@ -37,33 +34,55 @@ * public * * Static Data to be sent to the UI. - * Static data differs from normal data in that it's large data that should be sent infrequently - * This is implemented optionally for heavy uis that would be sending a lot of redundant data - * frequently. - * Gets squished into one object on the frontend side, but the static part is cached. + * + * Static data differs from normal data in that it's large data that should be + * sent infrequently. This is implemented optionally for heavy uis that would + * be sending a lot of redundant data frequently. Gets squished into one + * object on the frontend side, but the static part is cached. * * required user mob The mob interacting with the UI. * - * return list Statuic Data to be sent to the UI. - **/ + * return list Static Data to be sent to the UI. + */ /datum/proc/ui_static_data(mob/user) return list() /** * public * - * Forces an update on static data. Should be done manually whenever something happens to change static data. + * Forces an update on static data. Should be done manually whenever something + * happens to change static data. * * required user the mob currently interacting with the ui * optional ui ui to be updated - * optional ui_key ui key of ui to be updated - * -**/ -/datum/proc/update_static_data(mob/user, datum/tgui/ui, ui_key = "main") - ui = SStgui.try_update_ui(user, src, ui_key, ui) + */ +/datum/proc/update_static_data(mob/user, datum/tgui/ui) if(!ui) - return //If there was no ui to update, there's no static data to update either. - ui.push_data(null, ui_static_data(), TRUE) + ui = SStgui.get_open_ui(user, src) + if(ui) + ui.send_full_update() + +/** + * public + * + * Will force an update on static data for all viewers. + * Should be done manually whenever something happens to + * change static data. + */ +/datum/proc/update_static_data_for_all_viewers() + for (var/datum/tgui/window as anything in open_uis) + window.send_full_update() + +/** + * public + * + * Will force an update on non-static data for all viewers. + * Use when you are manually controlling UI data updates, + * such as when you are not using the auto-update system. + */ +/datum/proc/update_data_for_all_viewers() + for(var/datum/tgui/ui as anything in open_uis) + ui.send_update() /** * public @@ -74,26 +93,25 @@ * required action string The action/button that has been invoked by the user. * required params list A list of parameters attached to the button. * - * return bool If the UI should be updated or not. - **/ + * return bool If the user's input has been handled and the UI should update. + */ /datum/proc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - if(!ui || ui.status != UI_INTERACTIVE) - return 1 // If UI is not interactive or usr calling Topic is not the UI user, bail. + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_UI_ACT, usr, action, params) + // If UI is not interactive or usr calling Topic is not the UI user, bail. + if(ui?.status != UI_INTERACTIVE) + return TRUE /** * public * - * Called on an object when a tgui object is being created, allowing you to customise the html - * For example: inserting a custom stylesheet that you need in the head - * - * For this purpose, some tags are available in the html, to be parsed out with replacetext - * (customheadhtml) - Additions to the head tag + * Called on an object when a tgui object is being created, allowing you to + * push various assets to tgui, for examples spritesheets. * - * required html the html base text - * - **/ -/datum/proc/ui_base_html(html) - return html + * return list List of asset datums or file paths. + */ +/datum/proc/ui_assets(mob/user) + return list() /** * private @@ -101,24 +119,56 @@ * The UI's host object (usually src_object). * This allows modules/datums to have the UI attached to them, * and be a part of another object. - **/ + */ /datum/proc/ui_host(mob/user) return src // Default src. +/** + * private + * + * The UI's state controller to be used for created uis + * This is a proc over a var for memory reasons + */ +/datum/proc/ui_state(mob/user) + return GLOB.default_state + /** * global * - * Used to track UIs for a mob. - **/ -/mob/var/list/open_uis = list() + * Associative list of JSON-encoded shared states that were set by + * tgui clients. + */ +/datum/var/list/tgui_shared_states + /** - * public + * global * - * Called on a UI's object when the UI is closed, not to be confused with client/verb/uiclose(), which closes the ui window + * Tracks open UIs for a user. + */ +/mob/var/list/tgui_open_uis = list() + +/** + * global * + * Tracks open windows for a user. + */ +/client/var/list/tgui_windows = list() + +/** + * global * - **/ -/datum/proc/ui_close() + * TRUE if cache was reloaded by tgui dev server at least once. + */ +/client/var/tgui_cache_reloaded = FALSE + +/** + * public + * + * Called on a UI's object when the UI is closed, not to be confused with + * client/verb/uiclose(), which closes the ui window + */ +/datum/proc/ui_close(mob/user) + SIGNAL_HANDLER /** * verb @@ -127,18 +177,71 @@ * Must be a verb so winset() can call it. * * required uiref ref The UI that was closed. - **/ -/client/verb/uiclose(ref as text) + */ +/client/verb/uiclose(window_id as text) // Name the verb, and hide it from the user panel. set name = "uiclose" - set hidden = 1 + set hidden = TRUE + var/mob/user = src?.mob + if(!user) + return + // Close all tgui datums based on window_id. + SStgui.force_close_window(user, window_id) + +/** + * Middleware for /client/Topic. + * + * return bool If TRUE, prevents propagation of the topic call. + */ +/proc/tgui_Topic(href_list) + // Skip non-tgui topics + if(!href_list["tgui"]) + return FALSE + var/type = href_list["type"] + // Unconditionally collect tgui logs + if(type == "log") + var/context = href_list["window_id"] + if (href_list["ns"]) + context += " ([href_list["ns"]])" + log_tgui(usr, href_list["message"], + context = context) + // Reload all tgui windows + if(type == "cacheReloaded") + if(!check_rights(R_ADMIN) || usr.client.tgui_cache_reloaded) + return TRUE + // Mark as reloaded + usr.client.tgui_cache_reloaded = TRUE + // Notify windows + var/list/windows = usr.client.tgui_windows + for(var/window_id in windows) + var/datum/tgui_window/window = windows[window_id] + if (window.status == TGUI_WINDOW_READY) + window.on_message(type, null, href_list) + return TRUE + // Locate window + var/window_id = href_list["window_id"] + var/datum/tgui_window/window + if(window_id) + window = usr.client.tgui_windows[window_id] + if(!window) + log_tgui(usr, + "Error: Couldn't find the window datum, force closing.", + context = window_id) + SStgui.force_close_window(usr, window_id) + return TRUE + + // Decode payload + var/payload + if(href_list["payload"]) + var/payload_text = href_list["payload"] + + if (!rustg_json_is_valid(payload_text)) + log_tgui(usr, "Error: Invalid JSON") + return TRUE - // Get the UI based on the ref. - var/datum/tgui/ui = locate(ref) + payload = json_decode(payload_text) - // If we found the UI, close it. - if(istype(ui)) - ui.close() - // Unset machine just to be sure. - if(src && src.mob) - src.mob.unset_machine() + // Pass message to window + if(window) + window.on_message(type, payload, href_list) + return TRUE diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index aafb42ea1c9..4bebe8b917b 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -1,8 +1,10 @@ -/** - * tgui states +/*! + * Base state and helpers for states. Just does some sanity checks, + * implement a proper state for in-depth checks. * - * Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks. - **/ + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ /** * public @@ -13,7 +15,7 @@ * required state datum/ui_state The state to check. * * return UI_state The state of the UI. - **/ + */ /datum/proc/ui_status(mob/user, datum/ui_state/state) var/src_object = ui_host(user) . = UI_CLOSE @@ -21,14 +23,11 @@ return if(isobserver(user)) - // If they turn on ghost AI control, admins can always interact. - if(IsAdminGhost(user)) - . = max(., UI_INTERACTIVE) - // Regular ghosts can always at least view if in range. - var/clientviewlist = getviewsize(user.client.view) - if(get_dist(src_object, user) < max(clientviewlist[1],clientviewlist[2])) - . = max(., UI_UPDATE) + if(user.client) + var/clientviewlist = getviewsize(user.client.view) + if(get_dist(src_object, user) < max(clientviewlist[1], clientviewlist[2])) + . = max(., UI_UPDATE) // Check if the state allows interaction var/result = state.can_use_topic(src_object, user) @@ -44,9 +43,10 @@ * required user mob The mob who opened/is using the UI. * * return UI_state The state of the UI. - **/ + */ /datum/ui_state/proc/can_use_topic(src_object, mob/user) - return UI_CLOSE // Don't allow interaction by default. + // Don't allow interaction by default. + return UI_CLOSE /** * public @@ -54,36 +54,24 @@ * Standard interaction/sanity checks. Different mob types may have overrides. * * return UI_state The state of the UI. - **/ + */ /mob/proc/shared_ui_interaction(src_object) - if(!client) // Close UIs if mindless. + // Close UIs if mindless. + if(!client && !HAS_TRAIT(src, TRAIT_PRESERVE_UI_WITHOUT_CLIENT)) return UI_CLOSE - else if(stat) // Disable UIs if unconcious. + // Disable UIs if unconscious. + else if(stat) return UI_DISABLED - else if(incapacitated(IGNORE_GRAB)) // Update UIs if incapicitated but concious. + // Update UIs if incapicitated but conscious. + else if(incapacitated(IGNORE_GRAB)) return UI_UPDATE return UI_INTERACTIVE -/mob/living/shared_ui_interaction(src_object) +/mob/living/shared_ui_interaction(atom/src_object) . = ..() - if(!(mobility_flags & MOBILITY_UI) && . == UI_INTERACTIVE) + if(!(mobility_flags & MOBILITY_UI) && !(src_object.interaction_flags_atom & INTERACT_ATOM_IGNORE_MOBILITY) && . == UI_INTERACTIVE) return UI_UPDATE -/** - * public - * - * Check the distance for a living mob. - * Really only used for checks outside the context of a mob. - * Otherwise, use shared_living_ui_distance(). - * - * required src_object The object which owns the UI. - * required user mob The mob who opened/is using the UI. - * - * return UI_state The state of the UI. - **/ -/atom/proc/contents_ui_distance(src_object, mob/living/user) - return user.shared_living_ui_distance(src_object) // Just call this mob's check. - /** * public * @@ -92,19 +80,20 @@ * required src_object atom/movable The object which owns the UI. * * return UI_state The state of the UI. - **/ -/mob/living/proc/shared_living_ui_distance(atom/movable/src_object) - if(!(src_object in view(src))) // If the object is obscured, close it. + */ +/mob/living/proc/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE, allow_tk = TRUE) + // If the object is obscured, close it. + if(viewcheck && !(src_object in view(src))) return UI_CLOSE - var/dist = get_dist(src_object, src) - if(dist <= 1) // Open and interact if 1-0 tiles away. + // Open and interact if 1-0 tiles away. + if(dist <= 1) return UI_INTERACTIVE - else if(dist <= 2) // View only if 2-3 tiles away. + // View only if 2-3 tiles away. + else if(dist <= 2) return UI_UPDATE - else if(dist <= 5) // Disable if 5 tiles away. + // Disable if 5 tiles away. + else if(dist <= 5) return UI_DISABLED - return UI_CLOSE // Otherwise, we got nothing. - -/mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object) - return ..() + // Otherwise, we got nothing. + return UI_CLOSE diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm index ad1854448be..29708c28a59 100644 --- a/code/modules/tgui/states/default.dm +++ b/code/modules/tgui/states/default.dm @@ -1,8 +1,14 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + /** * tgui state: default_state * - * Checks a number of things -- mostly physical distance for humans and view for robots. - **/ + * Checks a number of things -- mostly physical distance for humans + * and view for robots. + */ GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new) @@ -14,12 +20,7 @@ GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new) /mob/living/default_can_use_topic(src_object) . = shared_ui_interaction(src_object) - if(. > UI_CLOSE && loc) - . = min(., loc.contents_ui_distance(src_object, src)) // Check the distance... - if(. == UI_INTERACTIVE) // Non-human living mobs can only look, not touch. - return UI_UPDATE - -/mob/living/carbon/human/default_can_use_topic(src_object) - . = shared_ui_interaction(src_object) - if(. > UI_CLOSE) + if(. > UI_CLOSE && loc) //must not be in nullspace. . = min(., shared_living_ui_distance(src_object)) // Check the distance... + if(. == UI_INTERACTIVE && !IsAdvancedToolUser(src)) // unhandy living mobs can only look, not touch. + return UI_UPDATE diff --git a/code/modules/tgui/subsystem.dm b/code/modules/tgui/subsystem.dm deleted file mode 100644 index 07b792d2d92..00000000000 --- a/code/modules/tgui/subsystem.dm +++ /dev/null @@ -1,259 +0,0 @@ -/** - * tgui subsystem - * - * Contains all tgui state and subsystem code. - **/ - -/** - * public - * - * Get a open UI given a user, src_object, and ui_key and try to update it with data. - * - * required user mob The mob who opened/is using the UI. - * required src_object datum The object/datum which owns the UI. - * required ui_key string The ui_key of the UI. - * optional ui datum/tgui The UI to be updated, if it exists. - * optional force_open bool If the UI should be re-opened instead of updated. - * - * return datum/tgui The found UI. - **/ -/datum/controller/subsystem/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = FALSE) - if(isnull(ui)) // No UI was passed, so look for one. - ui = get_open_ui(user, src_object, ui_key) - - if(!isnull(ui)) - var/data = src_object.ui_data(user) // Get data from the src_object. - if(!force_open) // UI is already open; update it. - ui.push_data(data) - else // Re-open it anyways. - ui.reinitialize(null, data) - return ui // We found the UI, return it. - else - return null // We couldn't find a UI. - -/** - * private - * - * Get a open UI given a user, src_object, and ui_key. - * - * required user mob The mob who opened/is using the UI. - * required src_object datum The object/datum which owns the UI. - * required ui_key string The ui_key of the UI. - * - * return datum/tgui The found UI. - **/ -/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key) - var/src_object_key = "[REF(src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return null // No UIs open. - else if(isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list)) - return null // No UIs open for this object. - - for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) // Find UIs for this object. - if(ui.user == user) // Make sure we have the right user - return ui - - return null // Couldn't find a UI! - -/** - * private - * - * Update all UIs attached to src_object. - * - * required src_object datum The object/datum which owns the UIs. - * - * return int The number of UIs updated. - **/ -/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object) - var/src_object_key = "[REF(src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 // Couldn't find any UIs for this object. - - var/update_count = 0 - for(var/ui_key in open_uis[src_object_key]) - for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) - if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid. - ui.process(force = 1) // Update the UI. - update_count++ // Count each UI we update. - return update_count - -/** - * private - * - * Close all UIs attached to src_object. - * - * required src_object datum The object/datum which owns the UIs. - * - * return int The number of UIs closed. - **/ -/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object) - var/src_object_key = "[REF(src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 // Couldn't find any UIs for this object. - - var/close_count = 0 - for(var/ui_key in open_uis[src_object_key]) - for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) - if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid. - ui.close() // Close the UI. - close_count++ // Count each UI we close. - return close_count - -/** - * private - * - * Close *ALL* UIs - * - * return int The number of UIs closed. - **/ -/datum/controller/subsystem/tgui/proc/close_all_uis() - var/close_count = 0 - for(var/src_object_key in open_uis) - for(var/ui_key in open_uis[src_object_key]) - for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) - if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid. - ui.close() // Close the UI. - close_count++ // Count each UI we close. - return close_count - -/** - * private - * - * Update all UIs belonging to a user. - * - * required user mob The mob who opened/is using the UI. - * optional src_object datum If provided, only update UIs belonging this src_object. - * optional ui_key string If provided, only update UIs with this UI key. - * - * return int The number of UIs updated. - **/ -/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null) - if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) - return 0 // Couldn't find any UIs for this user. - - var/update_count = 0 - for(var/datum/tgui/ui in user.open_uis) - if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) - ui.process(force = 1) // Update the UI. - update_count++ // Count each UI we upadte. - return update_count - -/** - * private - * - * Close all UIs belonging to a user. - * - * required user mob The mob who opened/is using the UI. - * optional src_object datum If provided, only close UIs belonging this src_object. - * optional ui_key string If provided, only close UIs with this UI key. - * - * return int The number of UIs closed. - **/ -/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null) - if(!length(user.open_uis) && !length(user.browser_modals)) - return FALSE // Couldn't find any UIs for this user. - - var/close_count = 0 - for(var/datum/tgui/ui in user.open_uis) - if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) - ui.close() // Close the UI. - close_count++ // Count each UI we close. - - for(var/datum/browser/modal/modal in user.browser_modals) - modal.close() - close_count++ - return close_count - -/** - * private - * - * Add a UI to the list of open UIs. - * - * required ui datum/tgui The UI to be added. - **/ -/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui) - var/src_object_key = "[REF(ui.src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - open_uis[src_object_key] = list(ui.ui_key = list()) // Make a list for the ui_key and src_object. - else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) - open_uis[src_object_key][ui.ui_key] = list() // Make a list for the ui_key. - - // Append the UI to all the lists. - ui.user.open_uis |= ui - var/list/uis = open_uis[src_object_key][ui.ui_key] - uis |= ui - processing_uis |= ui - -/** - * private - * - * Remove a UI from the list of open UIs. - * - * required ui datum/tgui The UI to be removed. - * - * return bool If the UI was removed or not. - **/ -/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui) - var/src_object_key = "[REF(ui.src_object)]" - if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 // It wasn't open. - else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) - return 0 // It wasn't open. - - processing_uis.Remove(ui) // Remove it from the list of processing UIs. - if(ui.user) // If the user exists, remove it from them too. - ui.user.open_uis.Remove(ui) - var/Ukey = ui.ui_key - var/list/uis = open_uis[src_object_key][Ukey] // Remove it from the list of open UIs. - uis.Remove(ui) - if(!uis.len) - var/list/uiobj = open_uis[src_object_key] - uiobj.Remove(Ukey) - if(!uiobj.len) - open_uis.Remove(src_object_key) - - return 1 // Let the requester know we did it. - -/** - * private - * - * Handle client logout, by closing all their UIs. - * - * required user mob The mob which logged out. - * - * return int The number of UIs closed. - **/ -/datum/controller/subsystem/tgui/proc/on_logout(mob/user) - return close_user_uis(user) - -/** - * private - * - * Handle clients switching mobs, by transferring their UIs. - * - * required user source The client's original mob. - * required user target The client's new mob. - * - * return bool If the UIs were transferred. - **/ -/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target) - if(!length(source?.open_uis) && !length(source?.browser_modals)) - return FALSE - - if(isnull(target.open_uis) || !islist(target.open_uis)) - target.open_uis = list() // Create a list for the new mob if needed. - - for(var/datum/tgui/ui in source.open_uis) - ui.user = target // Inform the UIs of their new owner. - target.open_uis.Add(ui) // Transfer all the UIs. - - for(var/datum/browser/modal/modal in source.browser_modals) - modal.user = target - modal.UnregisterSignal(source, COMSIG_PARENT_QDELETING) - modal.RegisterSignal(target, COMSIG_PARENT_QDELETING, TYPE_PROC_REF(/datum/browser, user_deleted)) - target.browser_modals.Add(modal) - - // Clear the old list. - source.open_uis.Cut() - source.browser_modals.Cut() - return TRUE diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index c5a3f403323..2562952ea22 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -1,49 +1,45 @@ -/** - * tgui - * - * /tg/station user interface library - **/ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ /** * tgui datum (represents a UI). - **/ + */ /datum/tgui /// The mob who opened/is using the UI. var/mob/user /// The object which owns the UI. var/datum/src_object - /// The title of te UI. + /// The title of the UI. var/title - /// The ui_key of the UI. This allows multiple UIs for one src_object. - var/ui_key /// The window_id for browse() and onclose(). - var/window_id - /// The window width. - var/width = 0 - /// The window height - var/height = 0 - /// The style to be used for this UI. - var/style = "nanotrasen" + var/datum/tgui_window/window + /// Key that is used for remembering the window geometry. + var/window_key + /// Deprecated: Window size. + var/window_size /// The interface (template) to be used for this UI. var/interface /// Update the UI every MC tick. var/autoupdate = TRUE /// If the UI has been initialized yet. var/initialized = FALSE - /// The data (and datastructure) used to initialize the UI. - var/list/initial_data - /// The static data used to initialize the UI. - var/list/initial_static_data + /// Time of opening the window. + var/opened_at + /// Stops further updates when close() was called. + var/closing = FALSE /// The status/visibility of the UI. var/status = UI_INTERACTIVE + /// Timed refreshing state + var/refreshing = FALSE /// Topic state used to determine status/interactability. var/datum/ui_state/state = null - /// The parent UI. - var/datum/tgui/master_ui - /// Children of this UI. - var/list/datum/tgui/children = list() - var/custom_browser_id = FALSE - var/ui_screen = "home" + /// Rate limit client refreshes to prevent DoS. + COOLDOWN_DECLARE(refresh_cooldown) + + /// The id of any ByondUi elements that we have opened + var/list/open_byondui_elements /** * public @@ -52,313 +48,335 @@ * * required user mob The mob who opened/is using the UI. * required src_object datum The object or datum which owns the UI. - * required ui_key string The ui_key of the UI. * required interface string The interface used to render the UI. * optional title string The title of the UI. - * optional width int The window width. - * optional height int The window height. - * optional master_ui datum/tgui The parent UI. - * optional state datum/ui_state The state used to determine status. + * optional ui_x int Deprecated: Window width. + * optional ui_y int Deprecated: Window height. * * return datum/tgui The requested UI. - **/ -/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state, browser_id = null) + */ +/datum/tgui/New(mob/user, datum/src_object, interface, title, ui_x, ui_y) + log_tgui(user, + "new [interface] fancy [user?.client?.prefs.tgui_fancy]", + src_object = src_object) src.user = user src.src_object = src_object - src.ui_key = ui_key - src.window_id = browser_id ? browser_id : "[REF(src_object)]-[ui_key]" // DO NOT replace with \ref here. src_object could potentially be tagged - src.custom_browser_id = browser_id ? TRUE : FALSE - - set_interface(interface) - + src.window_key = "[REF(src_object)]-main" + src.interface = interface if(title) - src.title = sanitize(title) - if(width) - src.width = width - if(height) - src.height = height + src.title = title + src.state = src_object.ui_state(user) + // Deprecated + if(ui_x && ui_y) + src.window_size = list(ui_x, ui_y) - src.master_ui = master_ui - if(master_ui) - master_ui.children += src - src.state = state - if(user.client) - if(user.client.holder) - var/datum/asset/assets = get_asset_datum(/datum/asset/group/tgui) - assets.send(user) +/datum/tgui/Destroy() + user = null + src_object = null + return ..() /** * public * * Open this UI (and initialize it with data). - **/ + * + * return bool - TRUE if a new pooled window is opened, FALSE in all other situations including if a new pooled window didn't open because one already exists. + */ /datum/tgui/proc/open() if(!user.client) - return // Bail if there is no client. - - update_status(push = FALSE) // Update the window status. + return FALSE + if(window) + return FALSE + process_status() if(status < UI_UPDATE) - return // Bail if we're not supposed to open. - - var/window_size - if(width && height) // If we have a width and height, use them. - window_size = "size=[width]x[height];" + return FALSE + window = SStgui.request_pooled_window(user) + if(!window) + return FALSE + opened_at = world.time + window.acquire_lock(src) + if(!window.is_ready()) + window.initialize( + strict_mode = TRUE, + fancy = user.client.prefs.tgui_fancy, + assets = list( + get_asset_datum(/datum/asset/simple/tgui), + )) else - window_size = "" + window.send_message("ping") + send_assets() + window.send_message("update", get_payload( + with_data = TRUE, + with_static_data = TRUE)) + SStgui.on_open(src) - // Remove titlebar and resize handles for a fancy window - var/have_title_bar - if(user.client.prefs.tgui_fancy) - have_title_bar = "titlebar=0;can_resize=0;" - else - have_title_bar = "titlebar=1;can_resize=1;" + return TRUE - // Generate page html - var/html - html = SStgui.basehtml - // Allow the src object to override the html if needed - html = src_object.ui_base_html(html) - // Replace template tokens with important UI data - // NOTE: Intentional \ref usage; tgui datums can't/shouldn't - // be tagged, so this is an effective unwrap - html = replacetextEx(html, "\[ref]", text_ref(src)) - html = replacetextEx(html, "\[style]", style) +/datum/tgui/proc/send_assets() + var/flush_queue = window.send_asset(get_asset_datum(/datum/asset/simple/namespaced/fontawesome)) + flush_queue |= window.send_asset(get_asset_datum(/datum/asset/json/icon_ref_map)) - // Open the window. - user << browse(html, "window=[window_id];can_minimize=0;auto_format=0;[window_size][have_title_bar]") - if (!custom_browser_id) - // Instruct the client to signal UI when the window is closed. - // NOTE: Intentional \ref usage; tgui datums can't/shouldn't - // be tagged, so this is an effective unwrap - winset(user, window_id, "on-close=\"uiclose \ref[src]\"") + for(var/datum/asset/asset in src_object.ui_assets(user)) + flush_queue |= window.send_asset(asset) - if(!initial_data) - initial_data = src_object.ui_data(user) - if(!initial_static_data) - initial_static_data = src_object.ui_static_data(user) + if(flush_queue) + user.client.browse_queue_flush() - SStgui.on_open(src) +/** + * public + * + * Close the UI. + * + * optional can_be_suspended bool + */ +/datum/tgui/proc/close(can_be_suspended = TRUE) + if(closing) + return + closing = TRUE + // If we don't have window_id, open proc did not have the opportunity + // to finish, therefore it's safe to skip this whole block. + if(window) + // Windows you want to keep are usually blue screens of death + // and we want to keep them around, to allow user to read + // the error message properly. + window.release_lock() + window.close(can_be_suspended) + src_object.ui_close(user) + SStgui.on_close(src) + + if(user.client) + terminate_byondui_elements() + + state = null + qdel(src) /** * public * - * Reinitialize the UI. - * (Possibly with a new interface and/or data). + * Closes all ByondUI elements, left dangling by a forceful TGUI exit, + * such as via Alt+F4, closing in non-fancy mode, or terminating the process * - * optional template string The name of the new interface. - * optional data list The new initial data. - **/ -/datum/tgui/proc/reinitialize(interface, list/data, list/static_data) - if(interface) - set_interface(interface) // Set a new interface. - if(data) - initial_data = data - if(static_data) - initial_static_data = static_data - open() + */ +/datum/tgui/proc/terminate_byondui_elements() + set waitfor = FALSE + + for(var/byondui_element in open_byondui_elements) + winset(user.client, byondui_element, list("parent" = "")) /** * public * - * Close the UI, and all its children. - **/ -/datum/tgui/proc/close() - user << browse(null, "window=[window_id]") // Close the window. - src_object.ui_close() - SStgui.on_close(src) - for(var/datum/tgui/child in children) // Loop through and close all children. - child.close() - children.Cut() - state = null - master_ui = null - qdel(src) + * Enable/disable auto-updating of the UI. + * + * required value bool Enable/disable auto-updating. + */ +/datum/tgui/proc/set_autoupdate(autoupdate) + src.autoupdate = autoupdate /** * public * - * Set the style for this UI. + * Replace current ui.state with a new one. * - * required style string The new UI style. - **/ -/datum/tgui/proc/set_style(style) - src.style = lowertext(style) + * required state datum/ui_state/state Next state + */ +/datum/tgui/proc/set_state(datum/ui_state/state) + src.state = state /** * public * - * Set the interface (template) for this UI. + * Makes an asset available to use in tgui. * - * required interface string The new UI interface. - **/ -/datum/tgui/proc/set_interface(interface) - src.interface = lowertext(interface) + * required asset datum/asset + * + * return bool - true if an asset was actually sent + */ +/datum/tgui/proc/send_asset(datum/asset/asset) + if(!window) + CRASH("send_asset() was called either without calling open() first or when open() did not return TRUE.") + return window.send_asset(asset) /** * public * - * Enable/disable auto-updating of the UI. + * Send a full update to the client (includes static data). * - * required state bool Enable/disable auto-updating. - **/ -/datum/tgui/proc/set_autoupdate(state = TRUE) - autoupdate = state + * optional custom_data list Custom data to send instead of ui_data. + * optional force bool Send an update even if UI is not interactive. + */ +/datum/tgui/proc/send_full_update(custom_data, force) + if(!user.client || !initialized || closing) + return + if(!COOLDOWN_FINISHED(src, refresh_cooldown)) + refreshing = TRUE + addtimer(CALLBACK(src, PROC_REF(send_full_update), custom_data, force), COOLDOWN_TIMELEFT(src, refresh_cooldown), TIMER_UNIQUE) + return + refreshing = FALSE + var/should_update_data = force || status >= UI_UPDATE + window.send_message("update", get_payload( + custom_data, + with_data = should_update_data, + with_static_data = TRUE)) + COOLDOWN_START(src, refresh_cooldown, TGUI_REFRESH_FULL_UPDATE_COOLDOWN) + +/** + * public + * + * Send a partial update to the client (excludes static data). + * + * optional custom_data list Custom data to send instead of ui_data. + * optional force bool Send an update even if UI is not interactive. + */ +/datum/tgui/proc/send_update(custom_data, force) + if(!user.client || !initialized || closing) + return + var/should_update_data = force || status >= UI_UPDATE + window.send_message("update", get_payload( + custom_data, + with_data = should_update_data)) /** * private * * Package the data to send to the UI, as JSON. - * This includes the UI data and config_data. * - * return string The packaged JSON. - **/ -/datum/tgui/proc/get_json(list/data, list/static_data) + * return list + */ +/datum/tgui/proc/get_payload(custom_data, with_data, with_static_data) var/list/json_data = list() - json_data["config"] = list( "title" = title, "status" = status, - "screen" = ui_screen, - "style" = style, - "interface" = interface, - "fancy" = user.client.prefs.tgui_fancy, - "locked" = user.client.prefs.tgui_lock && !custom_browser_id, - "window" = window_id, - // Intentional \ref usage; tgui datums can't/shouldn't be tagged so this is an effective unwrap - "ref" = text_ref(src) + "interface" = list( + "name" = interface, + ), + "refreshing" = refreshing, + "window" = list( + "key" = window_key, + "size" = window_size, + "fancy" = user.client.prefs.tgui_fancy, + ), + "client" = list( + "ckey" = user.client.ckey, + "address" = user.client.address, + "computer_id" = user.client.computer_id, + ), + "user" = list( + "name" = "[user]", + "observer" = isobserver(user), + ), ) - - if(!isnull(data)) + var/data = custom_data || with_data && src_object.ui_data(user) + if(data) json_data["data"] = data - if(!isnull(static_data)) + var/static_data = with_static_data && src_object.ui_static_data(user) + if(static_data) json_data["static_data"] = static_data - - // Generate the JSON. - var/json = json_encode(json_data) - // Strip #255/improper. - json = replacetext(json, "\proper", "") - json = replacetext(json, "\improper", "") - return json + if(src_object.tgui_shared_states) + json_data["shared"] = src_object.tgui_shared_states + return json_data /** * private * - * Handle clicks from the UI. - * Call the src_object's ui_act() if status is UI_INTERACTIVE. - * If the src_object's ui_act() returns 1, update all UIs attacked to it. - **/ -/datum/tgui/Topic(href, href_list) - if(user != usr) - return // Something is not right here. - - var/action = href_list["action"] - var/params = href_list; params -= "action" - - switch(action) - if("tgui:initialize") - user << output(url_encode(get_json(initial_data, initial_static_data)), "[custom_browser_id ? window_id : "[window_id].browser"]:initialize") - initialized = TRUE - if("tgui:view") - if(params["screen"]) - ui_screen = params["screen"] - SStgui.update_uis(src_object) - if("tgui:log") - // Force window to show frills on fatal errors - if(params["fatal"]) - winset(user, window_id, "titlebar=1;can-resize=1;size=600x600") - log_message(params["log"]) - if("tgui:link") - user << link(params["url"]) - if("tgui:fancy") - user.client.prefs.tgui_fancy = TRUE - if("tgui:nofrills") - user.client.prefs.tgui_fancy = FALSE - else - update_status(push = FALSE) // Update the window state. - if(src_object.ui_act(action, params, src, state)) // Call ui_act() on the src_object. - SStgui.update_uis(src_object) // Update if the object requested it. + * Run an update cycle for this UI. Called internally by SStgui + * every second or so. + */ +/datum/tgui/process(delta_time, force) + if(closing) + return -/** - * private - * - * Update the UI. - * Only updates the data if update is true, otherwise only updates the status. - * - * optional force bool If the UI should be forced to update. - **/ -/datum/tgui/process(force = FALSE) var/datum/host = src_object.ui_host(user) - if(!src_object || !host || !user) // If the object or user died (or something else), abort. - close() + // If the object or user died (or something else), abort. + if(QDELETED(src_object) || QDELETED(host) || QDELETED(user) || QDELETED(window)) + close(can_be_suspended = FALSE) return - if(status && (force || autoupdate)) - update() // Update the UI if the status and update settings allow it. - else - update_status(push = TRUE) // Otherwise only update status. + // Validate ping + if(!initialized && world.time - opened_at > TGUI_PING_TIMEOUT) + log_tgui(user, "Error: Zombie window detected, closing.", + window = window, + src_object = src_object) + close(can_be_suspended = FALSE) + return -/** - * private - * - * Push data to an already open UI. - * - * required data list The data to send. - * optional force bool If the update should be sent regardless of state. - **/ -/datum/tgui/proc/push_data(data, static_data, force = FALSE) - update_status(push = FALSE) // Update the window state. - if(!initialized) - return // Cannot update UI if it is not set up yet. - if(status <= UI_DISABLED && !force) - return // Cannot update UI, we have no visibility. + // Update through a normal call to ui_interact + if(status != UI_DISABLED && (autoupdate || force)) + src_object.ui_interact(user, src) + return - // Send the new JSON to the update() Javascript function. - user << output(url_encode(get_json(data, static_data)), "[custom_browser_id ? window_id : "[window_id].browser"]:update") + // Update status only + var/needs_update = process_status() + if(status <= UI_CLOSE) + close() + return -/** - * private - * - * Updates the UI by interacting with the src_object again, which will hopefully - * call try_ui_update on it. - * - * optional force_open bool If force_open should be passed to ui_interact. - **/ -/datum/tgui/proc/update(force_open = FALSE) - src_object.ui_interact(user, ui_key, src, force_open, master_ui, state) + if(needs_update) + window.send_message("update", get_payload()) /** * private * - * Update the status/visibility of the UI for its user. - * - * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). - **/ -/datum/tgui/proc/update_status(push = FALSE) - var/status = src_object.ui_status(user, state) - if(master_ui) - status = min(status, master_ui.status) - - set_status(status, push) - if(status == UI_CLOSE) - close() + * Updates the status, and returns TRUE if status has changed. + */ +/datum/tgui/proc/process_status() + var/prev_status = status + status = src_object.ui_status(user, state) + return prev_status != status /** * private * - * Set the status/visibility of the UI. - * - * required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE). - * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). - **/ -/datum/tgui/proc/set_status(status, push = FALSE) - if(src.status != status) // Only update if status has changed. - if(src.status == UI_DISABLED) - src.status = status - if(push) - update() - else - src.status = status - if(status == UI_DISABLED || push) // Update if the UI just because disabled, or a push is requested. - push_data(null, force = TRUE) - -/datum/tgui/proc/log_message(message) - log_tgui("[user] ([user.ckey]) using \"[title]\":\n[message]") + * Callback for handling incoming tgui messages. + */ +/datum/tgui/proc/on_message(type, list/payload, list/href_list) + // Pass act type messages to ui_act + if(type && copytext(type, 1, 5) == "act/") + var/act_type = copytext(type, 5) + log_tgui(user, "Action: [act_type] [href_list["payload"]]", + window = window, + src_object = src_object) + process_status() + DEFAULT_QUEUE_OR_CALL_VERB(VERB_CALLBACK(src, PROC_REF(on_act_message), act_type, payload, state)) + return FALSE + switch(type) + if("ready") + // Send a full update when the user manually refreshes the UI + if(initialized) + send_full_update() + initialized = TRUE + if("ping/reply") + initialized = TRUE + if("suspend") + close(can_be_suspended = TRUE) + if("close") + close(can_be_suspended = FALSE) + if("log") + if(href_list["fatal"]) + close(can_be_suspended = FALSE) + if("setSharedState") + if(status != UI_INTERACTIVE) + return + LAZYINITLIST(src_object.tgui_shared_states) + src_object.tgui_shared_states[href_list["key"]] = href_list["value"] + SStgui.update_uis(src_object) + if(TGUI_MANAGED_BYONDUI_TYPE_RENDER) + var/byond_ui_id = payload[TGUI_MANAGED_BYONDUI_PAYLOAD_ID] + if(!byond_ui_id || LAZYLEN(open_byondui_elements) > TGUI_MANAGED_BYONDUI_LIMIT) + return + + LAZYOR(open_byondui_elements, byond_ui_id) + if(TGUI_MANAGED_BYONDUI_TYPE_UNMOUNT) + var/byond_ui_id = payload[TGUI_MANAGED_BYONDUI_PAYLOAD_ID] + if(!byond_ui_id) + return + + LAZYREMOVE(open_byondui_elements, byond_ui_id) + +/// Wrapper for behavior to potentially wait until the next tick if the server is overloaded +/datum/tgui/proc/on_act_message(act_type, payload, state) + if(QDELETED(src) || QDELETED(src_object)) + return + if(src_object.ui_act(act_type, payload, src, state)) + SStgui.update_uis(src_object) diff --git a/code/modules/tgui_panel/tgui_window.dm b/code/modules/tgui/tgui_window.dm similarity index 80% rename from code/modules/tgui_panel/tgui_window.dm rename to code/modules/tgui/tgui_window.dm index 556f5872d08..b8709c9a6d0 100644 --- a/code/modules/tgui_panel/tgui_window.dm +++ b/code/modules/tgui/tgui_window.dm @@ -11,6 +11,7 @@ var/is_browser = FALSE var/status = TGUI_WINDOW_CLOSED var/locked = FALSE + var/visible = FALSE var/datum/tgui/locked_by var/datum/subscriber_object var/subscriber_delegate @@ -24,27 +25,8 @@ var/initial_inline_html var/initial_inline_js var/initial_inline_css - var/mouse_event_macro_set = FALSE - - /** - * Static list used to map in macros that will then emit execute events to the tgui window - * A small disclaimer though I'm no tech wiz: I don't think it's possible to map in right or middle - * clicks in the current state, as they're keywords rather than modifiers. - */ - var/static/list/byondToTguiEventMap = list( - "MouseDown" = "byond/mousedown", - "MouseUp" = "byond/mouseup", - "Ctrl" = "byond/ctrldown", - "Ctrl+UP" = "byond/ctrlup", - ) - -/** - * global - * - * Tracks open windows for a user. - */ -/client/var/list/tgui_windows = list() + var/list/oversized_payloads = list() /** * public @@ -240,12 +222,11 @@ /datum/tgui_window/proc/close(can_be_suspended = TRUE) if(!client) return - if(mouse_event_macro_set) - remove_mouse_macro() if(can_be_suspended && can_be_suspended()) log_tgui(client, context = "[id]/close (suspending)", window = src) + visible = FALSE status = TGUI_WINDOW_READY send_message("suspend") return @@ -253,6 +234,7 @@ context = "[id]/close", window = src) release_lock() + visible = FALSE status = TGUI_WINDOW_CLOSED message_queue = null // Do not close the window to give user some time @@ -321,7 +303,10 @@ if(istype(asset, /datum/asset/spritesheet)) var/datum/asset/spritesheet/spritesheet = asset send_message("asset/stylesheet", spritesheet.css_filename()) - //send_raw_message(asset.get_serialized_url_mappings()) + else if(istype(asset, /datum/asset/spritesheet_batched)) + var/datum/asset/spritesheet_batched/spritesheet = asset + send_message("asset/stylesheet", spritesheet.css_filename()) + send_raw_message(asset.get_serialized_url_mappings()) /** * private @@ -369,10 +354,10 @@ status = TGUI_WINDOW_READY flush_message_queue() // Pass message to UI that requested the lock - //if(locked && locked_by) - // var/prevent_default = locked_by.on_message(type, payload, href_list) - // if(prevent_default) - // return + if(locked && locked_by) + var/prevent_default = locked_by.on_message(type, payload, href_list) + if(prevent_default) + return // Pass message to the subscriber else if(subscriber_object) var/prevent_default = call( @@ -384,6 +369,9 @@ switch(type) if("ping") send_message("ping/reply", payload) + if("visible") + visible = TRUE + SEND_SIGNAL(src, COMSIG_TGUI_WINDOW_VISIBLE, client) if("suspend") close(can_be_suspended = TRUE) if("close") @@ -392,38 +380,48 @@ client << link(href_list["url"]) if("cacheReloaded") reinitialize() - //if("chat/resend") - // SSchat.handle_resend(client, payload) + // if("chat/resend") + // SSchat.handle_resend(client, payload) + if("oversizedPayloadRequest") + var/payload_id = payload["id"] + var/chunk_count = payload["chunkCount"] + var/permit_payload = chunk_count <= CONFIG_GET(number/tgui_max_chunk_count) + if(permit_payload) + create_oversized_payload(payload_id, payload["type"], chunk_count) + send_message("oversizePayloadResponse", list("allow" = permit_payload, "id" = payload_id)) + if("payloadChunk") + var/payload_id = payload["id"] + append_payload_chunk(payload_id, payload["chunk"]) + send_message("acknowlegePayloadChunk", list("id" = payload_id)) -/* /datum/tgui_window/vv_edit_var(var_name, var_value) return var_name != NAMEOF(src, id) && ..() -*/ -/datum/tgui_window/proc/set_mouse_macro() - if(mouse_event_macro_set) +/datum/tgui_window/proc/create_oversized_payload(payload_id, message_type, chunk_count) + if(oversized_payloads[payload_id]) + stack_trace("Attempted to create oversized tgui payload with duplicate ID.") return + oversized_payloads[payload_id] = list( + "type" = message_type, + "count" = chunk_count, + "chunks" = list(), + "timeout" = addtimer(CALLBACK(src, PROC_REF(remove_oversized_payload), payload_id), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE) + ) - for(var/mouseMacro in byondToTguiEventMap) - var/command_template = ".output CONTROL PAYLOAD" - var/event_message = TGUI_CREATE_MESSAGE(byondToTguiEventMap[mouseMacro], null) - var target_control = is_browser \ - ? "[id]:update" \ - : "[id].browser:update" - var/with_id = replacetext(command_template, "CONTROL", target_control) - var/full_command = replacetext(with_id, "PAYLOAD", event_message) - - var/list/params = list() - params["parent"] = "default" //Technically this is external to tgui but whatever - params["name"] = mouseMacro - params["command"] = full_command - - winset(client, "[mouseMacro]Window[id]Macro", params) - mouse_event_macro_set = TRUE +/datum/tgui_window/proc/append_payload_chunk(payload_id, chunk) + var/list/payload = oversized_payloads[payload_id] + if(!payload) + return + var/list/chunks = payload["chunks"] + chunks += chunk + if(length(chunks) >= payload["count"]) + deltimer(payload["timeout"]) + var/message_type = payload["type"] + var/final_payload = chunks.Join() + remove_oversized_payload(payload_id) + on_message(message_type, json_decode(final_payload), list("type" = message_type, "payload" = final_payload, "tgui" = TRUE, "window_id" = id)) + else + payload["timeout"] = addtimer(CALLBACK(src, PROC_REF(remove_oversized_payload), payload_id), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE) -/datum/tgui_window/proc/remove_mouse_macro() - if(!mouse_event_macro_set) - stack_trace("Unsetting mouse macro on tgui window that has none") - for(var/mouseMacro in byondToTguiEventMap) - winset(client, null, "[mouseMacro]Window[id]Macro.parent=null") - mouse_event_macro_set = FALSE +/datum/tgui_window/proc/remove_oversized_payload(payload_id) + oversized_payloads -= payload_id diff --git a/code/modules/tgui_panel/tgui.dm b/code/modules/tgui_panel/tgui.dm deleted file mode 100644 index f1369a1142f..00000000000 --- a/code/modules/tgui_panel/tgui.dm +++ /dev/null @@ -1,81 +0,0 @@ -/** - * private - * - * Updates the status, and returns TRUE if status has changed. - */ -/datum/tgui/proc/process_status() - var/prev_status = status - status = src_object.ui_status(user, state) - return prev_status != status - -/** - * private - * - * Callback for handling incoming tgui messages. - */ -/* -/datum/tgui/proc/on_message(type, list/payload, list/href_list) - // Pass act type messages to ui_act - if(type && copytext(type, 1, 5) == "act/") - var/act_type = copytext(type, 5) - - var/id = href_list["packetId"] - if(!isnull(id)) - id = text2num(id) - - var/total = text2num(href_list["totalPackets"]) - - if(total > MAX_MESSAGE_CHUNKS) - return - - if(id == 1) - partial_packets = new /list(total) - - partial_packets[id] = href_list["packet"] - - if(id != total) - return - - var/assembled_payload = "" - for(var/packet in partial_packets) - assembled_payload += packet - - payload = json_decode(assembled_payload) - partial_packets = null - - log_tgui(user, "Action: [act_type] [href_list["payload"]]", - window = window, - src_object = src_object) - process_status() - //DEFAULT_QUEUE_OR_CALL_VERB(VERB_CALLBACK(src, PROC_REF(on_act_message), act_type, payload, state)) - on_act_message(act_type, payload, state) - return FALSE - switch(type) - if("ready") - // Send a full update when the user manually refreshes the UI - if(initialized) - send_full_update() - initialized = TRUE - if("ping/reply") - initialized = TRUE - if("suspend") - close(can_be_suspended = TRUE) - if("close") - close(can_be_suspended = FALSE) - if("log") - if(href_list["fatal"]) - close(can_be_suspended = FALSE) - if("setSharedState") - if(status != UI_INTERACTIVE) - return - LAZYINITLIST(src_object.tgui_shared_states) - src_object.tgui_shared_states[href_list["key"]] = href_list["value"] - SStgui.update_uis(src_object) -*/ -/// Wrapper for behavior to potentially wait until the next tick if the server is overloaded -/datum/tgui/proc/on_act_message(act_type, payload, state) - if(QDELETED(src) || QDELETED(src_object)) - return - if(src_object.ui_act(act_type, payload, src, state)) - SStgui.update_uis(src_object) - diff --git a/code/modules/tgui_panel/tgui_panel.dm b/code/modules/tgui_panel/tgui_panel.dm index 784526578d4..1b03aeb3184 100644 --- a/code/modules/tgui_panel/tgui_panel.dm +++ b/code/modules/tgui_panel/tgui_panel.dm @@ -12,11 +12,13 @@ var/datum/tgui_window/window var/broken = FALSE var/initialized_at + /// Each client notifies on protected playback, so this prevents spamming admins. + var/static/admins_warned = FALSE -/datum/tgui_panel/New(client/client) +/datum/tgui_panel/New(client/client, id) src.client = client - window = new(client, "browseroutput") - window.subscribe(src, .proc/on_message) + window = new(client, id) + window.subscribe(src, PROC_REF(on_message)) /datum/tgui_panel/Del() window.unsubscribe(src) @@ -37,16 +39,22 @@ * Initializes tgui panel. */ /datum/tgui_panel/proc/initialize(force = FALSE) + set waitfor = FALSE + // Minimal sleep to defer initialization to after client constructor + sleep(1 TICKS) initialized_at = world.time // Perform a clean initialization -// window.initialize(inline_assets = list( -// get_asset_datum(/datum/asset/simple/tgui_common), -// get_asset_datum(/datum/asset/simple/tgui_panel), -// )) -// window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome)) -// window.send_asset(get_asset_datum(/datum/asset/spritesheet/chat)) + window.initialize( + strict_mode = TRUE, + assets = list( + get_asset_datum(/datum/asset/simple/tgui_panel), + )) + window.send_asset(get_asset_datum(/datum/asset/simple/namespaced/fontawesome)) + window.send_asset(get_asset_datum(/datum/asset/spritesheet_batched/chat)) + // Other setup request_telemetry() - addtimer(CALLBACK(src, .proc/on_initialize_timed_out), 2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(on_initialize_timed_out)), 5 SECONDS) + window.send_message("testTelemetryCommand") /** * private @@ -55,7 +63,7 @@ */ /datum/tgui_panel/proc/on_initialize_timed_out() // Currently does nothing but sending a message to old chat. - SEND_TEXT(client, "Failed to load fancy chat, click HERE to attempt to reload it.") + SEND_TEXT(client, span_userdanger("Failed to load fancy chat, click HERE to attempt to reload it.")) /** * private @@ -79,9 +87,18 @@ ), )) return TRUE + if(type == "audio/setAdminMusicVolume") client.admin_music_volume = payload["volume"] return TRUE + + if(type == "audio/protected") + if(!admins_warned) + message_admins(span_notice("Audio returned a protected playback error, likely due to being copyrighted.")) + admins_warned = TRUE + addtimer(VARSET_CALLBACK(src, admins_warned, FALSE), 10 SECONDS) + return TRUE + if(type == "telemetry") analyze_telemetry(payload) return TRUE @@ -93,28 +110,3 @@ */ /datum/tgui_panel/proc/send_roundrestart() window.send_message("roundrestart") - -/** -* Compiles a full list of verbs to be sent to the browser -* Sends the 2D verbs vector of (verb category, verb name) -*/ -/client/proc/init_verbs() - if(IsAdminAdvancedProcCall()) - return - var/list/verblist = list() - var/list/verbstoprocess = verbs.Copy() - if(mob) - verbstoprocess += mob.verbs - for(var/atom/movable/thing as anything in mob.contents) - verbstoprocess += thing.verbs - panel_tabs.Cut() // panel_tabs get reset in init_verbs on JS side anyway - for(var/procpath/verb_to_init as anything in verbstoprocess) - if(!verb_to_init) - continue - if(verb_to_init.hidden) - continue - if(!istext(verb_to_init.category)) - continue - panel_tabs |= verb_to_init.category - verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name) - src.stat_panel.send_message("init_verbs", list(panel_tabs = panel_tabs, verblist = verblist)) diff --git a/vanderlin.dme b/vanderlin.dme index c71ab849b50..d3883a68d4d 100644 --- a/vanderlin.dme +++ b/vanderlin.dme @@ -212,6 +212,7 @@ #include "code\__DEFINES\dcs\signals\signals_ai.dm" #include "code\__DEFINES\dcs\signals\signals_beam.dm" #include "code\__DEFINES\dcs\signals\signals_coven_powers.dm" +#include "code\__DEFINES\dcs\signals\signals_datum.dm" #include "code\__DEFINES\dcs\signals\signals_divine.dm" #include "code\__DEFINES\dcs\signals\signals_global.dm" #include "code\__DEFINES\dcs\signals\signals_hud.dm" @@ -224,6 +225,7 @@ #include "code\__DEFINES\dcs\signals\signals_spatial_grid.dm" #include "code\__DEFINES\dcs\signals\signals_spell.dm" #include "code\__DEFINES\dcs\signals\signals_subsystems.dm" +#include "code\__DEFINES\dcs\signals\signals_tgui.dm" #include "code\__DEFINES\dcs\signals\signals_tram.dm" #include "code\__DEFINES\dcs\signals\signals_turf.dm" #include "code\__DEFINES\dcs\signals\signals_twohand.dm" @@ -2185,6 +2187,7 @@ #include "code\modules\asset_cache\asset_client.dm" #include "code\modules\asset_cache\asset_configs.dm" #include "code\modules\asset_cache\asset_list.dm" +#include "code\modules\asset_cache\assets\icon_ref_map.dm" #include "code\modules\asset_cache\spritesheet\batched\batched_spritesheet.dm" #include "code\modules\asset_cache\spritesheet\batched\universal_icon.dm" #include "code\modules\asset_cache\spritesheet\legacy\legacy_spritesheet.dm" @@ -3677,8 +3680,8 @@ #include "code\modules\tgs\includes.dm" #include "code\modules\tgui\external.dm" #include "code\modules\tgui\states.dm" -#include "code\modules\tgui\subsystem.dm" #include "code\modules\tgui\tgui.dm" +#include "code\modules\tgui\tgui_window.dm" #include "code\modules\tgui\states\admin.dm" #include "code\modules\tgui\states\always.dm" #include "code\modules\tgui\states\conscious.dm" @@ -3698,9 +3701,7 @@ #include "code\modules\tgui_panel\audio.dm" #include "code\modules\tgui_panel\external.dm" #include "code\modules\tgui_panel\telemetry.dm" -#include "code\modules\tgui_panel\tgui.dm" #include "code\modules\tgui_panel\tgui_panel.dm" -#include "code\modules\tgui_panel\tgui_window.dm" #include "code\modules\tooltip\tooltip.dm" #include "code\modules\underworld\underworld.dm" #include "code\modules\unit_tests\_unit_tests.dm" From 4c9c410732c3e439b822670affcf155ed6c0ddfb Mon Sep 17 00:00:00 2001 From: CheffieGithub <113442598+CheffieGithub@users.noreply.github.com> Date: Fri, 6 Feb 2026 15:25:48 +0000 Subject: [PATCH 05/67] nothing will go wrong --- tgui-next/.editorconfig | 13 - tgui-next/.eslintignore | 6 - tgui-next/.eslintrc.yml | 715 -- tgui-next/.gitattributes | 10 - tgui-next/.gitignore | 7 - tgui-next/README.md | 795 -- tgui-next/bin/tgui | 166 - tgui-next/bin/tgui-build.bat | 5 - tgui-next/bin/tgui-dev-server.bat | 4 - tgui-next/docs/tutorial-and-examples.md | 245 - tgui-next/package.json | 19 - tgui-next/packages/common/collections.js | 166 - tgui-next/packages/common/fp.js | 41 - tgui-next/packages/common/logging.js | 66 - tgui-next/packages/common/math.js | 19 - tgui-next/packages/common/package.json | 6 - tgui-next/packages/common/react.js | 67 - tgui-next/packages/common/redux.js | 65 - .../packages/common/string.babel-plugin.cjs | 70 - tgui-next/packages/common/string.js | 127 - tgui-next/packages/common/vector.js | 45 - tgui-next/packages/tgui-dev-server/index.js | 22 - .../packages/tgui-dev-server/link/client.js | 137 - .../packages/tgui-dev-server/link/retrace.js | 76 - .../packages/tgui-dev-server/link/server.js | 115 - .../packages/tgui-dev-server/package.json | 12 - .../packages/tgui-dev-server/reloader.js | 66 - tgui-next/packages/tgui-dev-server/util.js | 26 - tgui-next/packages/tgui-dev-server/webpack.js | 54 - .../packages/tgui/assets/bg-nanotrasen.svg | 49 - .../packages/tgui/assets/bg-syndicate.svg | Bin 82 -> 0 bytes tgui-next/packages/tgui/backend.js | 57 - tgui-next/packages/tgui/byond.js | 84 - .../tgui/components/AnimatedNumber.js | 77 - .../packages/tgui/components/BlockQuote.js | 15 - tgui-next/packages/tgui/components/Box.js | 157 - tgui-next/packages/tgui/components/Button.js | 106 - tgui-next/packages/tgui/components/Chart.js | 121 - .../packages/tgui/components/ColorBox.js | 19 - tgui-next/packages/tgui/components/Dimmer.js | 19 - tgui-next/packages/tgui/components/Flex.js | 66 - tgui-next/packages/tgui/components/Grid.js | 31 - tgui-next/packages/tgui/components/Icon.js | 30 - tgui-next/packages/tgui/components/Input.js | 109 - .../packages/tgui/components/LabeledList.js | 75 - .../packages/tgui/components/NoticeBox.js | 16 - .../packages/tgui/components/NumberInput.js | 250 - .../packages/tgui/components/ProgressBar.js | 50 - tgui-next/packages/tgui/components/Section.js | 44 - tgui-next/packages/tgui/components/Table.js | 59 - tgui-next/packages/tgui/components/Tabs.js | 134 - .../packages/tgui/components/TitleBar.js | 42 - tgui-next/packages/tgui/components/Toast.js | 57 - tgui-next/packages/tgui/components/Tooltip.js | 20 - tgui-next/packages/tgui/components/index.js | 21 - tgui-next/packages/tgui/constants.js | 214 - tgui-next/packages/tgui/drag.js | 158 - tgui-next/packages/tgui/hotkeys.js | 252 - tgui-next/packages/tgui/index.js | 166 - .../packages/tgui/interfaces/Achievements.js | 37 - .../packages/tgui/interfaces/AiAirlock.js | 198 - .../packages/tgui/interfaces/AirAlarm.js | 462 - .../tgui/interfaces/AirlockElectronics.js | 144 - tgui-next/packages/tgui/interfaces/Apc.js | 206 - .../tgui/interfaces/AtmosAlertConsole.js | 47 - .../tgui/interfaces/AtmosControlConsole.js | 98 - .../packages/tgui/interfaces/AtmosFilter.js | 54 - .../packages/tgui/interfaces/AtmosMixer.js | 68 - .../packages/tgui/interfaces/AtmosPump.js | 65 - .../tgui/interfaces/BluespaceArtillery.js | 82 - .../packages/tgui/interfaces/BorgPanel.js | 137 - .../packages/tgui/interfaces/BrigTimer.js | 57 - .../packages/tgui/interfaces/Canister.js | 123 - tgui-next/packages/tgui/interfaces/Cargo.js | 351 - .../tgui/interfaces/CellularEmporium.js | 56 - .../tgui/interfaces/CentcomPodLauncher.js | 452 - .../tgui/interfaces/ChemAcclimator.js | 76 - .../tgui/interfaces/ChemDebugSynthesizer.js | 84 - .../packages/tgui/interfaces/ChemDispenser.js | 180 - .../packages/tgui/interfaces/ChemFilter.js | 64 - .../packages/tgui/interfaces/ChemHeater.js | 76 - .../packages/tgui/interfaces/ChemMaster.js | 367 - .../packages/tgui/interfaces/ChemPress.js | 54 - .../packages/tgui/interfaces/ChemSplitter.js | 47 - .../tgui/interfaces/ChemSynthesizer.js | 42 - .../packages/tgui/interfaces/CodexGigas.js | 105 - .../tgui/interfaces/ComputerFabricator.js | 406 - tgui-next/packages/tgui/interfaces/Crayon.js | 63 - .../packages/tgui/interfaces/CrewConsole.js | 133 - tgui-next/packages/tgui/interfaces/Cryo.js | 111 - .../packages/tgui/interfaces/DisposalUnit.js | 70 - tgui-next/packages/tgui/interfaces/Gps.js | 126 - .../packages/tgui/interfaces/KitchenSink.js | 278 - .../packages/tgui/interfaces/LanguageMenu.js | 97 - .../packages/tgui/interfaces/MedicalKiosk.js | 269 - tgui-next/packages/tgui/interfaces/Mint.js | 48 - .../packages/tgui/interfaces/NtosMain.js | 77 - .../tgui/interfaces/NtosSupermatterMonitor.js | 179 - .../packages/tgui/interfaces/NtosWrapper.js | 110 - .../tgui/interfaces/OperatingComputer.js | 159 - .../tgui/interfaces/OreRedemptionMachine.js | 146 - .../tgui/interfaces/PersonalCrafting.js | 178 - .../tgui/interfaces/PortableGenerator.js | 93 - .../packages/tgui/interfaces/PowerMonitor.js | 223 - tgui-next/packages/tgui/interfaces/Radio.js | 110 - .../tgui/interfaces/RapidPipeDispenser.js | 190 - tgui-next/packages/tgui/interfaces/SMES.js | 130 - .../tgui/interfaces/ShuttleManipulator.js | 188 - .../packages/tgui/interfaces/SmartVend.js | 63 - .../packages/tgui/interfaces/SolarControl.js | 119 - .../tgui/interfaces/StationAlertConsole.js | 59 - .../tgui/interfaces/SuitStorageUnit.js | 117 - .../packages/tgui/interfaces/TankDispenser.js | 40 - .../packages/tgui/interfaces/ThermoMachine.js | 79 - .../tgui/interfaces/TurbineComputer.js | 55 - .../tgui/interfaces/VaultController.js | 29 - tgui-next/packages/tgui/interfaces/Wires.js | 64 - .../tgui/interfaces/common/BeakerContents.js | 19 - .../common/InterfaceLockNoticeBox.js | 37 - tgui-next/packages/tgui/layout.js | 89 - tgui-next/packages/tgui/logging.js | 44 - tgui-next/packages/tgui/package.json | 31 - tgui-next/packages/tgui/polyfills.js | 5 - tgui-next/packages/tgui/public/shim-css-om.js | 38 - tgui-next/packages/tgui/public/shim-dom4.js | 969 -- .../packages/tgui/public/shim-html5shiv.js | 329 - tgui-next/packages/tgui/public/shim-ie8.js | 835 -- .../packages/tgui/public/tgui-fallback.html | 68 - tgui-next/packages/tgui/public/tgui-main.html | 122 - .../packages/tgui/public/tgui.bundle.css | 1 - tgui-next/packages/tgui/public/tgui.bundle.js | 3 - tgui-next/packages/tgui/refocus.js | 12 - tgui-next/packages/tgui/routes.js | 311 - tgui-next/packages/tgui/store.js | 30 - .../tgui/styles/atomic/candystripe.scss | 3 - .../packages/tgui/styles/atomic/color.scss | 16 - .../packages/tgui/styles/atomic/text.scss | 23 - tgui-next/packages/tgui/styles/base.scss | 10 - tgui-next/packages/tgui/styles/colors.scss | 79 - .../tgui/styles/components/Button.scss | 115 - .../tgui/styles/components/ColorBox.scss | 7 - .../tgui/styles/components/FatalError.scss | 92 - .../packages/tgui/styles/components/Flex.scss | 15 - .../tgui/styles/components/Input.scss | 52 - .../tgui/styles/components/LabeledList.scss | 43 - .../tgui/styles/components/Layout.scss | 101 - .../tgui/styles/components/NoticeBox.scss | 28 - .../tgui/styles/components/NtosHeader.scss | 15 - .../tgui/styles/components/NtosWrapper.scss | 19 - .../tgui/styles/components/NumberInput.scss | 68 - .../tgui/styles/components/ProgressBar.scss | 50 - .../tgui/styles/components/Section.scss | 66 - .../tgui/styles/components/Table.scss | 33 - .../packages/tgui/styles/components/Tabs.scss | 36 - .../tgui/styles/components/TitleBar.scss | 74 - .../tgui/styles/components/Tooltip.scss | 106 - tgui-next/packages/tgui/styles/functions.scss | 60 - tgui-next/packages/tgui/styles/main.scss | 44 - tgui-next/packages/tgui/styles/reset.scss | 47 - .../packages/tgui/styles/themes/ntos.scss | 40 - .../tgui/styles/themes/syndicate.scss | 55 - tgui-next/packages/tgui/webpack.config.js | 200 - tgui-next/yarn.lock | 6342 ---------- tgui/.babelrc | 5 - tgui/.gitattributes | 22 +- tgui/.gitignore | 11 +- tgui/.prettierignore | 12 + tgui/.prettierrc.yml | 6 + tgui/LICENSE.md | 20 - tgui/README.md | 286 +- tgui/assets/tgui.css | 1 - tgui/assets/tgui.js | 22 - tgui/build.sh | 12 - tgui/build_assets.bat | 6 - tgui/bun.lock | 1399 ++ tgui/bunfig.toml | 2 + tgui/docs/chat-embedded-components.md | 82 + .../docs/converting-old-tgui-interfaces.md | 106 +- tgui/docs/migration-to-v4-from-v3.md | 91 + tgui/docs/state-usage.md | 30 + tgui/docs/tgui-for-custom-html-popups.md | 267 + tgui/docs/tutorial-and-examples.md | 337 + tgui/docs/writing-tests.md | 19 + tgui/global.d.ts | 208 + tgui/gulp/css.js | 31 - tgui/gulp/flags.js | 7 - tgui/gulp/js.js | 68 - tgui/gulp/plugins.js | 21 - tgui/gulp/reload.js | 10 - tgui/gulp/size.js | 9 - tgui/gulpfile.babel.js | 12 - tgui/happydom.ts | 5 + tgui/install_dependencies.bat | 8 - tgui/package-lock.json | 10545 ---------------- tgui/package.json | 94 +- tgui/packages/common/assets.ts | 30 + tgui/packages/common/collections.ts | 50 + tgui/packages/common/package.json | 9 + tgui/packages/common/perf.ts | 72 + tgui/packages/common/storage.ts | 229 + tgui/packages/common/type-safety.test.ts | 53 + tgui/packages/common/type-safety.ts | 56 + tgui/packages/tgfont/.gitignore | 1 + tgui/packages/tgfont/README_ICON_TUTORIAL.md | 13 + tgui/packages/tgfont/icons/ATTRIBUTIONS.md | 8 + tgui/packages/tgfont/icons/air-tank-slash.svg | 1 + tgui/packages/tgfont/icons/air-tank.svg | 1 + tgui/packages/tgfont/icons/bad-touch.svg | 1 + tgui/packages/tgfont/icons/image-minus.svg | 1 + tgui/packages/tgfont/icons/image-plus.svg | 1 + .../packages/tgfont/icons/nanotrasen-logo.svg | 1 + tgui/packages/tgfont/icons/non-binary.svg | 1 + .../packages/tgfont/icons/prosthetic-full.svg | 1 + tgui/packages/tgfont/icons/prosthetic-leg.svg | 1 + tgui/packages/tgfont/icons/sound-minus.svg | 1 + tgui/packages/tgfont/icons/sound-plus.svg | 1 + tgui/packages/tgfont/icons/syndicate-logo.svg | 1 + tgui/packages/tgfont/package.json | 13 + tgui/packages/tgfont/static/tgfont.css | 65 + tgui/packages/tgfont/static/tgfont.woff2 | Bin 0 -> 2472 bytes tgui/packages/tgfont/svgtofont.mjs | 20 + tgui/packages/tgui-dev-server/dreamseeker.ts | 115 + tgui/packages/tgui-dev-server/index.ts | 31 + tgui/packages/tgui-dev-server/link/client.ts | 172 + tgui/packages/tgui-dev-server/link/retrace.ts | 88 + tgui/packages/tgui-dev-server/link/server.ts | 116 + tgui/packages/tgui-dev-server/logging.ts | 72 + tgui/packages/tgui-dev-server/package.json | 11 + tgui/packages/tgui-dev-server/reloader.ts | 133 + tgui/packages/tgui-dev-server/require.ts | 9 + tgui/packages/tgui-dev-server/util.ts | 40 + tgui/packages/tgui-dev-server/webpack.ts | 69 + tgui/packages/tgui-dev-server/winreg.ts | 52 + tgui/packages/tgui-panel/Notifications.tsx | 30 + tgui/packages/tgui-panel/Panel.tsx | 102 + tgui/packages/tgui-panel/app.tsx | 12 + .../tgui-panel/audio/NowPlayingWidget.tsx | 108 + tgui/packages/tgui-panel/audio/atoms.ts | 22 + tgui/packages/tgui-panel/audio/handlers.ts | 39 + tgui/packages/tgui-panel/audio/player.ts | 127 + .../tgui-panel/chat/ChatPageSettings.tsx | 113 + tgui/packages/tgui-panel/chat/ChatPanel.tsx | 76 + tgui/packages/tgui-panel/chat/ChatTabs.tsx | 61 + tgui/packages/tgui-panel/chat/atom.ts | 29 + tgui/packages/tgui-panel/chat/constants.ts | 165 + tgui/packages/tgui-panel/chat/handlers.ts | 58 + tgui/packages/tgui-panel/chat/helpers.ts | 101 + tgui/packages/tgui-panel/chat/migration.ts | 207 + tgui/packages/tgui-panel/chat/model.ts | 85 + tgui/packages/tgui-panel/chat/renderer.tsx | 648 + .../tgui-panel/chat/replaceInTextNode.ts | 216 + tgui/packages/tgui-panel/chat/types.ts | 25 + .../tgui-panel/chat/use-chat-pages.ts | 146 + .../tgui-panel/chat/use-chat-persistence.ts | 96 + .../tgui-panel/events/handlers/assets.ts | 8 + .../events/handlers/roundrestart.ts | 8 + tgui/packages/tgui-panel/events/listeners.ts | 28 + tgui/packages/tgui-panel/events/store.ts | 3 + tgui/packages/tgui-panel/game/atoms.ts | 40 + tgui/packages/tgui-panel/game/constants.ts | 7 + .../tgui-panel/game/use-keep-alive.ts | 16 + tgui/packages/tgui-panel/index.tsx | 65 + tgui/packages/tgui-panel/package.json | 17 + tgui/packages/tgui-panel/panelFocus.ts | 56 + .../tgui-panel/ping/PingIndicator.tsx | 30 + tgui/packages/tgui-panel/ping/atoms.ts | 11 + tgui/packages/tgui-panel/ping/constants.ts | 11 + tgui/packages/tgui-panel/ping/handlers.ts | 38 + tgui/packages/tgui-panel/ping/helpers.ts | 74 + tgui/packages/tgui-panel/reconnect.tsx | 41 + .../tgui-panel/settings/SettingsGeneral.tsx | 202 + .../tgui-panel/settings/SettingsPanel.tsx | 54 + .../tgui-panel/settings/SettingsStatPanel.tsx | 77 + .../tgui-panel/settings/TextHighlight.tsx | 164 + tgui/packages/tgui-panel/settings/atoms.ts | 55 + .../packages/tgui-panel/settings/constants.ts | 60 + tgui/packages/tgui-panel/settings/helpers.ts | 85 + .../packages/tgui-panel/settings/migration.ts | 117 + tgui/packages/tgui-panel/settings/scaling.ts | 58 + .../tgui-panel/settings/settingsImExport.ts | 92 + tgui/packages/tgui-panel/settings/themes.ts | 80 + tgui/packages/tgui-panel/settings/types.ts | 45 + .../tgui-panel/settings/use-highlights.ts | 109 + .../tgui-panel/settings/use-settings.ts | 56 + .../tgui-panel/styles/components/Chat.scss | 94 + .../styles/components/Notifications.scss | 26 + .../tgui-panel/styles/components/Ping.scss | 28 + .../styles/components/UnreadCount.scss | 12 + tgui/packages/tgui-panel/styles/main.scss | 41 + .../tgui-panel/styles/tgchat/chat-dark.scss | 1269 ++ .../tgui-panel/styles/tgchat/chat-light.scss | 1250 ++ .../tgui-panel/styles/themes/light.scss | 33 + .../tgui-panel/telemetry/constants.ts | 1 + .../packages/tgui-panel/telemetry/handlers.ts | 102 + tgui/packages/tgui-panel/telemetry/helpers.ts | 16 + .../packages/tgui-say/ChannelIterator.test.ts | 49 + tgui/packages/tgui-say/ChannelIterator.ts | 50 + tgui/packages/tgui-say/ChatHistory.test.ts | 52 + tgui/packages/tgui-say/ChatHistory.ts | 59 + tgui/packages/tgui-say/TguiSay.tsx | 330 + tgui/packages/tgui-say/constants.ts | 35 + tgui/packages/tgui-say/helpers.ts | 72 + tgui/packages/tgui-say/index.tsx | 16 + tgui/packages/tgui-say/package.json | 12 + tgui/packages/tgui-say/styles/colors.scss | 43 + tgui/packages/tgui-say/styles/main.scss | 39 + tgui/packages/tgui-say/styles/styles.scss | 112 + tgui/packages/tgui-say/timers.ts | 28 + tgui/packages/tgui-setup/helpers.js | 520 + tgui/packages/tgui-setup/ntos-error.css | 113 + tgui/packages/tgui-setup/package.json | 14 + tgui/packages/tgui/App.tsx | 11 + tgui/packages/tgui/__mocks__/byond.ts | 30 + tgui/packages/tgui/__mocks__/layouts.tsx | 32 + tgui/packages/tgui/__mocks__/setup.ts | 21 + tgui/packages/tgui/assets.ts | 5 + .../tgui/assets/transparency_checkerboard.svg | 10 + tgui/packages/tgui/backend.ts | 102 + tgui/packages/tgui/constants.test.ts | 77 + tgui/packages/tgui/constants.ts | 370 + tgui/packages/tgui/constants/theme.ts | 31 + tgui/packages/tgui/debug/KitchenSink.tsx | 110 + tgui/packages/tgui/debug/use-debug.ts | 27 + tgui/packages/tgui/drag.ts | 362 + tgui/packages/tgui/events/README.md | 114 + tgui/packages/tgui/events/act.ts | 101 + tgui/packages/tgui/events/handlers/assets.ts | 27 + .../packages/tgui/events/handlers/chunking.ts | 66 + tgui/packages/tgui/events/handlers/ping.ts | 5 + .../packages/tgui/events/handlers/suspense.ts | 55 + tgui/packages/tgui/events/handlers/update.ts | 100 + tgui/packages/tgui/events/listeners.ts | 29 + tgui/packages/tgui/events/store.ts | 37 + tgui/packages/tgui/events/types.ts | 49 + tgui/packages/tgui/focus.ts | 25 + tgui/packages/tgui/index.tsx | 51 + tgui/packages/tgui/layouts/Layout.tsx | 79 + tgui/packages/tgui/layouts/NtosWindow.tsx | 161 + tgui/packages/tgui/layouts/Pane.tsx | 56 + tgui/packages/tgui/layouts/TitleBar.tsx | 73 + tgui/packages/tgui/layouts/Window.tsx | 199 + tgui/packages/tgui/layouts/index.ts | 10 + tgui/packages/tgui/logging.ts | 68 + tgui/packages/tgui/package.json | 23 + tgui/packages/tgui/process.ts | 30 + tgui/packages/tgui/renderer.ts | 60 + tgui/packages/tgui/routes.tsx | 135 + tgui/packages/tgui/sanitize.ts | 82 + tgui/packages/tgui/stack.ts | 28 + .../tgui/styles/assets/bg-deforest.svg | 3 + tgui/packages/tgui/styles/base.scss | 21 + tgui/packages/tgui/styles/colors.scss | 58 + tgui/packages/tgui/styles/css-variables.scss | 13 + tgui/packages/tgui/styles/functions.scss | 24 + .../tgui/styles/interfaces/Accounting.scss | 42 + .../tgui/styles/interfaces/AlertModal.scss | 30 + .../tgui/styles/interfaces/AnomalyTower.scss | 33 + .../styles/interfaces/AntagInfoHeretic.scss | 193 + .../tgui/styles/interfaces/Changelog.scss | 13 + .../tgui/styles/interfaces/ColorPicker.scss | 150 + .../tgui/styles/interfaces/CrewManifest.scss | 56 + .../styles/interfaces/DetectiveBoard.scss | 230 + .../tgui/styles/interfaces/Emojipedia.scss | 8 + .../interfaces/ExperimentConfigure.scss | 108 + .../tgui/styles/interfaces/Fabricator.scss | 207 + .../tgui/styles/interfaces/HellishRunes.scss | 20 + .../tgui/styles/interfaces/HotKeysHelp.scss | 4 + .../tgui/styles/interfaces/Hypertorus.scss | 158 + .../styles/interfaces/IntegratedCircuit.scss | 143 + .../tgui/styles/interfaces/LibraryAdmin.scss | 18 + .../styles/interfaces/LibraryComputer.scss | 11 + .../tgui/styles/interfaces/ListInput.scss | 30 + .../tgui/styles/interfaces/Mecha.scss | 41 + .../tgui/styles/interfaces/NtosMessenger.scss | 101 + .../tgui/styles/interfaces/NtosNotepad.scss | 43 + .../tgui/styles/interfaces/NuclearBomb.scss | 102 + .../styles/interfaces/OperatingComputer.scss | 25 + .../tgui/styles/interfaces/Orbit.scss | 19 + .../tgui/styles/interfaces/Paper.scss | 18 + .../styles/interfaces/PreferencesMenu.scss | 240 + .../styles/interfaces/RequestManager.scss | 101 + .../tgui/styles/interfaces/Roulette.scss | 96 + .../packages/tgui/styles/interfaces/Safe.scss | 92 + .../tgui/styles/interfaces/Techweb.scss | 68 + .../tgui/styles/interfaces/Trophycase.scss | 5 + .../tgui/styles/interfaces/Uplink.scss | 103 + tgui/packages/tgui/styles/layouts/Layout.scss | 16 + .../tgui/styles/layouts/NtosHeader.scss | 48 + .../tgui/styles/layouts/NtosWindow.scss | 26 + .../tgui/styles/layouts/TitleBar.scss | 93 + tgui/packages/tgui/styles/layouts/Window.scss | 77 + tgui/packages/tgui/styles/main.scss | 70 + tgui/packages/tgui/styles/reset.scss | 62 + tgui/public/helpers.min.js | 1 + tgui/public/iframe.html | 102 + tgui/public/ntos-error.min.css | 1 + tgui/public/tgui.html | 62 + tgui/reload.bat | 8 - tgui/rspack.config-dev.ts | 29 + tgui/rspack.config.ts | 140 + tgui/src/.babelrc | 8 - tgui/src/components/bar.ract | 16 - tgui/src/components/bar.styl | 32 - tgui/src/components/button.ract | 81 - tgui/src/components/button.styl | 56 - tgui/src/components/display.ract | 13 - tgui/src/components/display.styl | 33 - tgui/src/components/input.ract | 13 - tgui/src/components/input.styl | 19 - tgui/src/components/linegraph.ract | 88 - tgui/src/components/linegraph.styl | 2 - tgui/src/components/notice.ract | 3 - tgui/src/components/notice.styl | 27 - tgui/src/components/resize.ract | 29 - tgui/src/components/resize.styl | 12 - tgui/src/components/section.ract | 12 - tgui/src/components/section.styl | 44 - tgui/src/components/subdisplay.ract | 11 - tgui/src/components/subdisplay.styl | 11 - tgui/src/components/tabs.ract | 27 - tgui/src/components/tabs/tab.ract | 3 - tgui/src/components/titlebar.ract | 78 - tgui/src/components/titlebar.styl | 65 - tgui/src/components/warnings.ract | 47 - tgui/src/images/nanotrasen.svg | Bin 82 -> 0 bytes tgui/src/images/syndicate.svg | Bin 82 -> 0 bytes tgui/src/interfaces/acclimator.ract | 27 - tgui/src/interfaces/ai_airlock.ract | 131 - tgui/src/interfaces/airalarm.ract | 51 - tgui/src/interfaces/airalarm/back.ract | 1 - tgui/src/interfaces/airalarm/modes.ract | 14 - tgui/src/interfaces/airalarm/scrubbers.ract | 29 - tgui/src/interfaces/airalarm/status.ract | 30 - tgui/src/interfaces/airalarm/thresholds.ract | 31 - tgui/src/interfaces/airalarm/vents.ract | 42 - tgui/src/interfaces/airlock_electronics.ract | 29 - tgui/src/interfaces/airlock_electronics.styl | 10 - tgui/src/interfaces/apc.ract | 151 - tgui/src/interfaces/atmos_alert.ract | 14 - tgui/src/interfaces/atmos_control.ract | 40 - tgui/src/interfaces/atmos_filter.ract | 17 - tgui/src/interfaces/atmos_mixer.ract | 33 - tgui/src/interfaces/atmos_pump.ract | 19 - tgui/src/interfaces/borgopanel.ract | 46 - tgui/src/interfaces/brig_timer.ract | 18 - tgui/src/interfaces/bsa.ract | 26 - tgui/src/interfaces/canister.ract | 84 - tgui/src/interfaces/cargo.ract | 104 - tgui/src/interfaces/cargo_express.ract | 50 - tgui/src/interfaces/cellular_emporium.ract | 25 - tgui/src/interfaces/centcom_podlauncher.ract | 157 - tgui/src/interfaces/chem_dispenser.ract | 75 - tgui/src/interfaces/chem_heater.ract | 29 - tgui/src/interfaces/chem_master.ract | 112 - tgui/src/interfaces/chem_press.ract | 11 - tgui/src/interfaces/chem_splitter.ract | 6 - tgui/src/interfaces/chem_synthesizer.ract | 22 - tgui/src/interfaces/chemical_filter.ract | 20 - tgui/src/interfaces/codex_gigas.ract | 50 - tgui/src/interfaces/computer_fabricator.ract | 89 - tgui/src/interfaces/crayon.ract | 35 - tgui/src/interfaces/crew.ract | 138 - tgui/src/interfaces/cryo.ract | 53 - tgui/src/interfaces/disposal_unit.ract | 33 - tgui/src/interfaces/dna_vault.ract | 22 - tgui/src/interfaces/eightball.ract | 14 - .../interfaces/emergency_shuttle_console.ract | 30 - tgui/src/interfaces/engraved_message.ract | 29 - tgui/src/interfaces/error.ract | 3 - tgui/src/interfaces/exonet_node.ract | 14 - tgui/src/interfaces/gps.ract | 30 - tgui/src/interfaces/gulag_console.ract | 49 - tgui/src/interfaces/gulag_item_reclaimer.ract | 7 - tgui/src/interfaces/holodeck.ract | 21 - tgui/src/interfaces/implantchair.ract | 40 - tgui/src/interfaces/intellicard.ract | 42 - tgui/src/interfaces/keycard_auth.ract | 17 - tgui/src/interfaces/labor_claim_console.ract | 20 - tgui/src/interfaces/language_menu.ract | 48 - tgui/src/interfaces/launchpad_console.ract | 56 - tgui/src/interfaces/launchpad_remote.ract | 49 - .../interfaces/mech_bay_power_console.ract | 40 - tgui/src/interfaces/medical_kiosk.ract | 50 - tgui/src/interfaces/mulebot.ract | 60 - .../interfaces/nanite_chamber_control.ract | 80 - tgui/src/interfaces/nanite_cloud_control.ract | 114 - tgui/src/interfaces/nanite_comm_remote.ract | 41 - tgui/src/interfaces/nanite_program_hub.ract | 49 - tgui/src/interfaces/nanite_programmer.ract | 54 - tgui/src/interfaces/nanite_remote.ract | 36 - tgui/src/interfaces/notificationpanel.ract | 7 - tgui/src/interfaces/ntnet_relay.ract | 22 - tgui/src/interfaces/ntos_ai_restorer.ract | 78 - tgui/src/interfaces/ntos_card.ract | 228 - tgui/src/interfaces/ntos_configuration.ract | 67 - tgui/src/interfaces/ntos_file_manager.ract | 75 - tgui/src/interfaces/ntos_main.ract | 19 - tgui/src/interfaces/ntos_net_chat.ract | 71 - tgui/src/interfaces/ntos_net_dos.ract | 26 - tgui/src/interfaces/ntos_net_downloader.ract | 90 - tgui/src/interfaces/ntos_net_monitor.ract | 93 - tgui/src/interfaces/ntos_net_transfer.ract | 103 - tgui/src/interfaces/ntos_power_monitor.ract | 80 - tgui/src/interfaces/ntos_revelation.ract | 27 - tgui/src/interfaces/ntos_station_alert.ract | 14 - .../interfaces/ntos_supermatter_monitor.ract | 65 - tgui/src/interfaces/ntosheader.ract | 30 - tgui/src/interfaces/nuclear_bomb.ract | 68 - tgui/src/interfaces/operating_computer.ract | 66 - .../interfaces/ore_redemption_machine.ract | 101 - tgui/src/interfaces/pandemic.ract | 113 - tgui/src/interfaces/personal_crafting.ract | 172 - tgui/src/interfaces/portable_generator.ract | 65 - tgui/src/interfaces/portable_pump.ract | 54 - tgui/src/interfaces/portable_scrubber.ract | 44 - tgui/src/interfaces/power_monitor.ract | 77 - tgui/src/interfaces/radio.ract | 66 - tgui/src/interfaces/rdconsole.ract | 47 - tgui/src/interfaces/rdconsole/circuit.ract | 57 - tgui/src/interfaces/rdconsole/designview.ract | 48 - tgui/src/interfaces/rdconsole/destruct.ract | 25 - .../interfaces/rdconsole/diskopsdesign.ract | 34 - .../src/interfaces/rdconsole/diskopstech.ract | 19 - tgui/src/interfaces/rdconsole/nodeview.ract | 26 - tgui/src/interfaces/rdconsole/protolathe.ract | 62 - tgui/src/interfaces/rdconsole/rdheader.ract | 7 - tgui/src/interfaces/rdconsole/settings.ract | 6 - tgui/src/interfaces/rdconsole/techweb.ract | 15 - tgui/src/interfaces/reaction_chamber.ract | 10 - tgui/src/interfaces/roulette.ract | 95 - tgui/src/interfaces/roulette.styl | 55 - tgui/src/interfaces/rpd.ract | 84 - tgui/src/interfaces/sat_control.ract | 21 - tgui/src/interfaces/scanner_gate.ract | 19 - tgui/src/interfaces/scrubbing_types.ract | 4 - tgui/src/interfaces/shuttle_manipulator.ract | 20 - .../shuttle_manipulator/modification.ract | 38 - .../shuttle_manipulator/status.ract | 33 - .../shuttle_manipulator/templates.ract | 24 - tgui/src/interfaces/sleeper.ract | 42 - tgui/src/interfaces/slime_swap_body.ract | 22 - tgui/src/interfaces/smartvend.ract | 48 - tgui/src/interfaces/smes.ract | 70 - tgui/src/interfaces/smoke_machine.ract | 38 - tgui/src/interfaces/solar_control.ract | 46 - tgui/src/interfaces/space_heater.ract | 45 - tgui/src/interfaces/spawners_menu.ract | 18 - tgui/src/interfaces/station_alert.ract | 11 - tgui/src/interfaces/suit_storage_unit.ract | 41 - tgui/src/interfaces/synd_contract.ract | 148 - tgui/src/interfaces/synthesizer.ract | 12 - tgui/src/interfaces/tank_dispenser.ract | 8 - tgui/src/interfaces/tanks.ract | 35 - tgui/src/interfaces/thermomachine.ract | 25 - tgui/src/interfaces/turbine_computer.ract | 51 - tgui/src/interfaces/uplink.ract | 43 - tgui/src/interfaces/vault_controller.ract | 10 - tgui/src/interfaces/wires.ract | 16 - tgui/src/styles/clockwork.styl | 48 - tgui/src/styles/nanotrasen.styl | 9 - tgui/src/styles/syndicate.styl | 31 - tgui/src/tgui.js | 70 - tgui/src/tgui.ract | 57 - tgui/src/tgui.styl | 134 - tgui/src/util/byond.js | 70 - tgui/src/util/colors.styl | 10 - tgui/src/util/constants.js | 5 - tgui/src/util/dragresize.js | 59 - tgui/src/util/filter.js | 22 - tgui/src/util/math.js | 9 - tgui/src/util/misc.styl | 12 - tgui/src/util/text.js | 14 - tgui/src/util/text.styl | 17 - tgui/src/util/tooltip.styl | 55 - tgui/tsconfig.json | 32 + 575 files changed, 19111 insertions(+), 42820 deletions(-) delete mode 100644 tgui-next/.editorconfig delete mode 100644 tgui-next/.eslintignore delete mode 100644 tgui-next/.eslintrc.yml delete mode 100644 tgui-next/.gitattributes delete mode 100644 tgui-next/.gitignore delete mode 100644 tgui-next/README.md delete mode 100644 tgui-next/bin/tgui delete mode 100644 tgui-next/bin/tgui-build.bat delete mode 100644 tgui-next/bin/tgui-dev-server.bat delete mode 100644 tgui-next/docs/tutorial-and-examples.md delete mode 100644 tgui-next/package.json delete mode 100644 tgui-next/packages/common/collections.js delete mode 100644 tgui-next/packages/common/fp.js delete mode 100644 tgui-next/packages/common/logging.js delete mode 100644 tgui-next/packages/common/math.js delete mode 100644 tgui-next/packages/common/package.json delete mode 100644 tgui-next/packages/common/react.js delete mode 100644 tgui-next/packages/common/redux.js delete mode 100644 tgui-next/packages/common/string.babel-plugin.cjs delete mode 100644 tgui-next/packages/common/string.js delete mode 100644 tgui-next/packages/common/vector.js delete mode 100644 tgui-next/packages/tgui-dev-server/index.js delete mode 100644 tgui-next/packages/tgui-dev-server/link/client.js delete mode 100644 tgui-next/packages/tgui-dev-server/link/retrace.js delete mode 100644 tgui-next/packages/tgui-dev-server/link/server.js delete mode 100644 tgui-next/packages/tgui-dev-server/package.json delete mode 100644 tgui-next/packages/tgui-dev-server/reloader.js delete mode 100644 tgui-next/packages/tgui-dev-server/util.js delete mode 100644 tgui-next/packages/tgui-dev-server/webpack.js delete mode 100644 tgui-next/packages/tgui/assets/bg-nanotrasen.svg delete mode 100644 tgui-next/packages/tgui/assets/bg-syndicate.svg delete mode 100644 tgui-next/packages/tgui/backend.js delete mode 100644 tgui-next/packages/tgui/byond.js delete mode 100644 tgui-next/packages/tgui/components/AnimatedNumber.js delete mode 100644 tgui-next/packages/tgui/components/BlockQuote.js delete mode 100644 tgui-next/packages/tgui/components/Box.js delete mode 100644 tgui-next/packages/tgui/components/Button.js delete mode 100644 tgui-next/packages/tgui/components/Chart.js delete mode 100644 tgui-next/packages/tgui/components/ColorBox.js delete mode 100644 tgui-next/packages/tgui/components/Dimmer.js delete mode 100644 tgui-next/packages/tgui/components/Flex.js delete mode 100644 tgui-next/packages/tgui/components/Grid.js delete mode 100644 tgui-next/packages/tgui/components/Icon.js delete mode 100644 tgui-next/packages/tgui/components/Input.js delete mode 100644 tgui-next/packages/tgui/components/LabeledList.js delete mode 100644 tgui-next/packages/tgui/components/NoticeBox.js delete mode 100644 tgui-next/packages/tgui/components/NumberInput.js delete mode 100644 tgui-next/packages/tgui/components/ProgressBar.js delete mode 100644 tgui-next/packages/tgui/components/Section.js delete mode 100644 tgui-next/packages/tgui/components/Table.js delete mode 100644 tgui-next/packages/tgui/components/Tabs.js delete mode 100644 tgui-next/packages/tgui/components/TitleBar.js delete mode 100644 tgui-next/packages/tgui/components/Toast.js delete mode 100644 tgui-next/packages/tgui/components/Tooltip.js delete mode 100644 tgui-next/packages/tgui/components/index.js delete mode 100644 tgui-next/packages/tgui/constants.js delete mode 100644 tgui-next/packages/tgui/drag.js delete mode 100644 tgui-next/packages/tgui/hotkeys.js delete mode 100644 tgui-next/packages/tgui/index.js delete mode 100644 tgui-next/packages/tgui/interfaces/Achievements.js delete mode 100644 tgui-next/packages/tgui/interfaces/AiAirlock.js delete mode 100644 tgui-next/packages/tgui/interfaces/AirAlarm.js delete mode 100644 tgui-next/packages/tgui/interfaces/AirlockElectronics.js delete mode 100644 tgui-next/packages/tgui/interfaces/Apc.js delete mode 100644 tgui-next/packages/tgui/interfaces/AtmosAlertConsole.js delete mode 100644 tgui-next/packages/tgui/interfaces/AtmosControlConsole.js delete mode 100644 tgui-next/packages/tgui/interfaces/AtmosFilter.js delete mode 100644 tgui-next/packages/tgui/interfaces/AtmosMixer.js delete mode 100644 tgui-next/packages/tgui/interfaces/AtmosPump.js delete mode 100644 tgui-next/packages/tgui/interfaces/BluespaceArtillery.js delete mode 100644 tgui-next/packages/tgui/interfaces/BorgPanel.js delete mode 100644 tgui-next/packages/tgui/interfaces/BrigTimer.js delete mode 100644 tgui-next/packages/tgui/interfaces/Canister.js delete mode 100644 tgui-next/packages/tgui/interfaces/Cargo.js delete mode 100644 tgui-next/packages/tgui/interfaces/CellularEmporium.js delete mode 100644 tgui-next/packages/tgui/interfaces/CentcomPodLauncher.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemAcclimator.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemDebugSynthesizer.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemDispenser.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemFilter.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemHeater.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemMaster.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemPress.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemSplitter.js delete mode 100644 tgui-next/packages/tgui/interfaces/ChemSynthesizer.js delete mode 100644 tgui-next/packages/tgui/interfaces/CodexGigas.js delete mode 100644 tgui-next/packages/tgui/interfaces/ComputerFabricator.js delete mode 100644 tgui-next/packages/tgui/interfaces/Crayon.js delete mode 100644 tgui-next/packages/tgui/interfaces/CrewConsole.js delete mode 100644 tgui-next/packages/tgui/interfaces/Cryo.js delete mode 100644 tgui-next/packages/tgui/interfaces/DisposalUnit.js delete mode 100644 tgui-next/packages/tgui/interfaces/Gps.js delete mode 100644 tgui-next/packages/tgui/interfaces/KitchenSink.js delete mode 100644 tgui-next/packages/tgui/interfaces/LanguageMenu.js delete mode 100644 tgui-next/packages/tgui/interfaces/MedicalKiosk.js delete mode 100644 tgui-next/packages/tgui/interfaces/Mint.js delete mode 100644 tgui-next/packages/tgui/interfaces/NtosMain.js delete mode 100644 tgui-next/packages/tgui/interfaces/NtosSupermatterMonitor.js delete mode 100644 tgui-next/packages/tgui/interfaces/NtosWrapper.js delete mode 100644 tgui-next/packages/tgui/interfaces/OperatingComputer.js delete mode 100644 tgui-next/packages/tgui/interfaces/OreRedemptionMachine.js delete mode 100644 tgui-next/packages/tgui/interfaces/PersonalCrafting.js delete mode 100644 tgui-next/packages/tgui/interfaces/PortableGenerator.js delete mode 100644 tgui-next/packages/tgui/interfaces/PowerMonitor.js delete mode 100644 tgui-next/packages/tgui/interfaces/Radio.js delete mode 100644 tgui-next/packages/tgui/interfaces/RapidPipeDispenser.js delete mode 100644 tgui-next/packages/tgui/interfaces/SMES.js delete mode 100644 tgui-next/packages/tgui/interfaces/ShuttleManipulator.js delete mode 100644 tgui-next/packages/tgui/interfaces/SmartVend.js delete mode 100644 tgui-next/packages/tgui/interfaces/SolarControl.js delete mode 100644 tgui-next/packages/tgui/interfaces/StationAlertConsole.js delete mode 100644 tgui-next/packages/tgui/interfaces/SuitStorageUnit.js delete mode 100644 tgui-next/packages/tgui/interfaces/TankDispenser.js delete mode 100644 tgui-next/packages/tgui/interfaces/ThermoMachine.js delete mode 100644 tgui-next/packages/tgui/interfaces/TurbineComputer.js delete mode 100644 tgui-next/packages/tgui/interfaces/VaultController.js delete mode 100644 tgui-next/packages/tgui/interfaces/Wires.js delete mode 100644 tgui-next/packages/tgui/interfaces/common/BeakerContents.js delete mode 100644 tgui-next/packages/tgui/interfaces/common/InterfaceLockNoticeBox.js delete mode 100644 tgui-next/packages/tgui/layout.js delete mode 100644 tgui-next/packages/tgui/logging.js delete mode 100644 tgui-next/packages/tgui/package.json delete mode 100644 tgui-next/packages/tgui/polyfills.js delete mode 100644 tgui-next/packages/tgui/public/shim-css-om.js delete mode 100644 tgui-next/packages/tgui/public/shim-dom4.js delete mode 100644 tgui-next/packages/tgui/public/shim-html5shiv.js delete mode 100644 tgui-next/packages/tgui/public/shim-ie8.js delete mode 100644 tgui-next/packages/tgui/public/tgui-fallback.html delete mode 100644 tgui-next/packages/tgui/public/tgui-main.html delete mode 100644 tgui-next/packages/tgui/public/tgui.bundle.css delete mode 100644 tgui-next/packages/tgui/public/tgui.bundle.js delete mode 100644 tgui-next/packages/tgui/refocus.js delete mode 100644 tgui-next/packages/tgui/routes.js delete mode 100644 tgui-next/packages/tgui/store.js delete mode 100644 tgui-next/packages/tgui/styles/atomic/candystripe.scss delete mode 100644 tgui-next/packages/tgui/styles/atomic/color.scss delete mode 100644 tgui-next/packages/tgui/styles/atomic/text.scss delete mode 100644 tgui-next/packages/tgui/styles/base.scss delete mode 100644 tgui-next/packages/tgui/styles/colors.scss delete mode 100644 tgui-next/packages/tgui/styles/components/Button.scss delete mode 100644 tgui-next/packages/tgui/styles/components/ColorBox.scss delete mode 100644 tgui-next/packages/tgui/styles/components/FatalError.scss delete mode 100644 tgui-next/packages/tgui/styles/components/Flex.scss delete mode 100644 tgui-next/packages/tgui/styles/components/Input.scss delete mode 100644 tgui-next/packages/tgui/styles/components/LabeledList.scss delete mode 100644 tgui-next/packages/tgui/styles/components/Layout.scss delete mode 100644 tgui-next/packages/tgui/styles/components/NoticeBox.scss delete mode 100644 tgui-next/packages/tgui/styles/components/NtosHeader.scss delete mode 100644 tgui-next/packages/tgui/styles/components/NtosWrapper.scss delete mode 100644 tgui-next/packages/tgui/styles/components/NumberInput.scss delete mode 100644 tgui-next/packages/tgui/styles/components/ProgressBar.scss delete mode 100644 tgui-next/packages/tgui/styles/components/Section.scss delete mode 100644 tgui-next/packages/tgui/styles/components/Table.scss delete mode 100644 tgui-next/packages/tgui/styles/components/Tabs.scss delete mode 100644 tgui-next/packages/tgui/styles/components/TitleBar.scss delete mode 100644 tgui-next/packages/tgui/styles/components/Tooltip.scss delete mode 100644 tgui-next/packages/tgui/styles/functions.scss delete mode 100644 tgui-next/packages/tgui/styles/main.scss delete mode 100644 tgui-next/packages/tgui/styles/reset.scss delete mode 100644 tgui-next/packages/tgui/styles/themes/ntos.scss delete mode 100644 tgui-next/packages/tgui/styles/themes/syndicate.scss delete mode 100644 tgui-next/packages/tgui/webpack.config.js delete mode 100644 tgui-next/yarn.lock delete mode 100644 tgui/.babelrc create mode 100644 tgui/.prettierignore create mode 100644 tgui/.prettierrc.yml delete mode 100644 tgui/LICENSE.md delete mode 100644 tgui/assets/tgui.css delete mode 100644 tgui/assets/tgui.js delete mode 100755 tgui/build.sh delete mode 100644 tgui/build_assets.bat create mode 100644 tgui/bun.lock create mode 100644 tgui/bunfig.toml create mode 100644 tgui/docs/chat-embedded-components.md rename {tgui-next => tgui}/docs/converting-old-tgui-interfaces.md (87%) create mode 100644 tgui/docs/migration-to-v4-from-v3.md create mode 100644 tgui/docs/state-usage.md create mode 100644 tgui/docs/tgui-for-custom-html-popups.md create mode 100644 tgui/docs/tutorial-and-examples.md create mode 100644 tgui/docs/writing-tests.md create mode 100644 tgui/global.d.ts delete mode 100644 tgui/gulp/css.js delete mode 100644 tgui/gulp/flags.js delete mode 100644 tgui/gulp/js.js delete mode 100644 tgui/gulp/plugins.js delete mode 100644 tgui/gulp/reload.js delete mode 100644 tgui/gulp/size.js delete mode 100644 tgui/gulpfile.babel.js create mode 100644 tgui/happydom.ts delete mode 100644 tgui/install_dependencies.bat delete mode 100644 tgui/package-lock.json create mode 100644 tgui/packages/common/assets.ts create mode 100644 tgui/packages/common/collections.ts create mode 100644 tgui/packages/common/package.json create mode 100644 tgui/packages/common/perf.ts create mode 100644 tgui/packages/common/storage.ts create mode 100644 tgui/packages/common/type-safety.test.ts create mode 100644 tgui/packages/common/type-safety.ts create mode 100644 tgui/packages/tgfont/.gitignore create mode 100644 tgui/packages/tgfont/README_ICON_TUTORIAL.md create mode 100644 tgui/packages/tgfont/icons/ATTRIBUTIONS.md create mode 100644 tgui/packages/tgfont/icons/air-tank-slash.svg create mode 100644 tgui/packages/tgfont/icons/air-tank.svg create mode 100644 tgui/packages/tgfont/icons/bad-touch.svg create mode 100644 tgui/packages/tgfont/icons/image-minus.svg create mode 100644 tgui/packages/tgfont/icons/image-plus.svg create mode 100644 tgui/packages/tgfont/icons/nanotrasen-logo.svg create mode 100644 tgui/packages/tgfont/icons/non-binary.svg create mode 100644 tgui/packages/tgfont/icons/prosthetic-full.svg create mode 100644 tgui/packages/tgfont/icons/prosthetic-leg.svg create mode 100644 tgui/packages/tgfont/icons/sound-minus.svg create mode 100644 tgui/packages/tgfont/icons/sound-plus.svg create mode 100644 tgui/packages/tgfont/icons/syndicate-logo.svg create mode 100644 tgui/packages/tgfont/package.json create mode 100644 tgui/packages/tgfont/static/tgfont.css create mode 100644 tgui/packages/tgfont/static/tgfont.woff2 create mode 100644 tgui/packages/tgfont/svgtofont.mjs create mode 100644 tgui/packages/tgui-dev-server/dreamseeker.ts create mode 100644 tgui/packages/tgui-dev-server/index.ts create mode 100644 tgui/packages/tgui-dev-server/link/client.ts create mode 100644 tgui/packages/tgui-dev-server/link/retrace.ts create mode 100644 tgui/packages/tgui-dev-server/link/server.ts create mode 100644 tgui/packages/tgui-dev-server/logging.ts create mode 100644 tgui/packages/tgui-dev-server/package.json create mode 100644 tgui/packages/tgui-dev-server/reloader.ts create mode 100644 tgui/packages/tgui-dev-server/require.ts create mode 100644 tgui/packages/tgui-dev-server/util.ts create mode 100644 tgui/packages/tgui-dev-server/webpack.ts create mode 100644 tgui/packages/tgui-dev-server/winreg.ts create mode 100644 tgui/packages/tgui-panel/Notifications.tsx create mode 100644 tgui/packages/tgui-panel/Panel.tsx create mode 100644 tgui/packages/tgui-panel/app.tsx create mode 100644 tgui/packages/tgui-panel/audio/NowPlayingWidget.tsx create mode 100644 tgui/packages/tgui-panel/audio/atoms.ts create mode 100644 tgui/packages/tgui-panel/audio/handlers.ts create mode 100644 tgui/packages/tgui-panel/audio/player.ts create mode 100644 tgui/packages/tgui-panel/chat/ChatPageSettings.tsx create mode 100644 tgui/packages/tgui-panel/chat/ChatPanel.tsx create mode 100644 tgui/packages/tgui-panel/chat/ChatTabs.tsx create mode 100644 tgui/packages/tgui-panel/chat/atom.ts create mode 100644 tgui/packages/tgui-panel/chat/constants.ts create mode 100644 tgui/packages/tgui-panel/chat/handlers.ts create mode 100644 tgui/packages/tgui-panel/chat/helpers.ts create mode 100644 tgui/packages/tgui-panel/chat/migration.ts create mode 100644 tgui/packages/tgui-panel/chat/model.ts create mode 100644 tgui/packages/tgui-panel/chat/renderer.tsx create mode 100644 tgui/packages/tgui-panel/chat/replaceInTextNode.ts create mode 100644 tgui/packages/tgui-panel/chat/types.ts create mode 100644 tgui/packages/tgui-panel/chat/use-chat-pages.ts create mode 100644 tgui/packages/tgui-panel/chat/use-chat-persistence.ts create mode 100644 tgui/packages/tgui-panel/events/handlers/assets.ts create mode 100644 tgui/packages/tgui-panel/events/handlers/roundrestart.ts create mode 100644 tgui/packages/tgui-panel/events/listeners.ts create mode 100644 tgui/packages/tgui-panel/events/store.ts create mode 100644 tgui/packages/tgui-panel/game/atoms.ts create mode 100644 tgui/packages/tgui-panel/game/constants.ts create mode 100644 tgui/packages/tgui-panel/game/use-keep-alive.ts create mode 100644 tgui/packages/tgui-panel/index.tsx create mode 100644 tgui/packages/tgui-panel/package.json create mode 100644 tgui/packages/tgui-panel/panelFocus.ts create mode 100644 tgui/packages/tgui-panel/ping/PingIndicator.tsx create mode 100644 tgui/packages/tgui-panel/ping/atoms.ts create mode 100644 tgui/packages/tgui-panel/ping/constants.ts create mode 100644 tgui/packages/tgui-panel/ping/handlers.ts create mode 100644 tgui/packages/tgui-panel/ping/helpers.ts create mode 100644 tgui/packages/tgui-panel/reconnect.tsx create mode 100644 tgui/packages/tgui-panel/settings/SettingsGeneral.tsx create mode 100644 tgui/packages/tgui-panel/settings/SettingsPanel.tsx create mode 100644 tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx create mode 100644 tgui/packages/tgui-panel/settings/TextHighlight.tsx create mode 100644 tgui/packages/tgui-panel/settings/atoms.ts create mode 100644 tgui/packages/tgui-panel/settings/constants.ts create mode 100644 tgui/packages/tgui-panel/settings/helpers.ts create mode 100644 tgui/packages/tgui-panel/settings/migration.ts create mode 100644 tgui/packages/tgui-panel/settings/scaling.ts create mode 100644 tgui/packages/tgui-panel/settings/settingsImExport.ts create mode 100644 tgui/packages/tgui-panel/settings/themes.ts create mode 100644 tgui/packages/tgui-panel/settings/types.ts create mode 100644 tgui/packages/tgui-panel/settings/use-highlights.ts create mode 100644 tgui/packages/tgui-panel/settings/use-settings.ts create mode 100644 tgui/packages/tgui-panel/styles/components/Chat.scss create mode 100644 tgui/packages/tgui-panel/styles/components/Notifications.scss create mode 100644 tgui/packages/tgui-panel/styles/components/Ping.scss create mode 100644 tgui/packages/tgui-panel/styles/components/UnreadCount.scss create mode 100644 tgui/packages/tgui-panel/styles/main.scss create mode 100644 tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss create mode 100644 tgui/packages/tgui-panel/styles/tgchat/chat-light.scss create mode 100644 tgui/packages/tgui-panel/styles/themes/light.scss create mode 100644 tgui/packages/tgui-panel/telemetry/constants.ts create mode 100644 tgui/packages/tgui-panel/telemetry/handlers.ts create mode 100644 tgui/packages/tgui-panel/telemetry/helpers.ts create mode 100644 tgui/packages/tgui-say/ChannelIterator.test.ts create mode 100644 tgui/packages/tgui-say/ChannelIterator.ts create mode 100644 tgui/packages/tgui-say/ChatHistory.test.ts create mode 100644 tgui/packages/tgui-say/ChatHistory.ts create mode 100644 tgui/packages/tgui-say/TguiSay.tsx create mode 100644 tgui/packages/tgui-say/constants.ts create mode 100644 tgui/packages/tgui-say/helpers.ts create mode 100644 tgui/packages/tgui-say/index.tsx create mode 100644 tgui/packages/tgui-say/package.json create mode 100644 tgui/packages/tgui-say/styles/colors.scss create mode 100644 tgui/packages/tgui-say/styles/main.scss create mode 100644 tgui/packages/tgui-say/styles/styles.scss create mode 100644 tgui/packages/tgui-say/timers.ts create mode 100644 tgui/packages/tgui-setup/helpers.js create mode 100644 tgui/packages/tgui-setup/ntos-error.css create mode 100644 tgui/packages/tgui-setup/package.json create mode 100644 tgui/packages/tgui/App.tsx create mode 100644 tgui/packages/tgui/__mocks__/byond.ts create mode 100644 tgui/packages/tgui/__mocks__/layouts.tsx create mode 100644 tgui/packages/tgui/__mocks__/setup.ts create mode 100644 tgui/packages/tgui/assets.ts create mode 100644 tgui/packages/tgui/assets/transparency_checkerboard.svg create mode 100644 tgui/packages/tgui/backend.ts create mode 100644 tgui/packages/tgui/constants.test.ts create mode 100644 tgui/packages/tgui/constants.ts create mode 100644 tgui/packages/tgui/constants/theme.ts create mode 100644 tgui/packages/tgui/debug/KitchenSink.tsx create mode 100644 tgui/packages/tgui/debug/use-debug.ts create mode 100644 tgui/packages/tgui/drag.ts create mode 100644 tgui/packages/tgui/events/README.md create mode 100644 tgui/packages/tgui/events/act.ts create mode 100644 tgui/packages/tgui/events/handlers/assets.ts create mode 100644 tgui/packages/tgui/events/handlers/chunking.ts create mode 100644 tgui/packages/tgui/events/handlers/ping.ts create mode 100644 tgui/packages/tgui/events/handlers/suspense.ts create mode 100644 tgui/packages/tgui/events/handlers/update.ts create mode 100644 tgui/packages/tgui/events/listeners.ts create mode 100644 tgui/packages/tgui/events/store.ts create mode 100644 tgui/packages/tgui/events/types.ts create mode 100644 tgui/packages/tgui/focus.ts create mode 100644 tgui/packages/tgui/index.tsx create mode 100644 tgui/packages/tgui/layouts/Layout.tsx create mode 100644 tgui/packages/tgui/layouts/NtosWindow.tsx create mode 100644 tgui/packages/tgui/layouts/Pane.tsx create mode 100644 tgui/packages/tgui/layouts/TitleBar.tsx create mode 100644 tgui/packages/tgui/layouts/Window.tsx create mode 100644 tgui/packages/tgui/layouts/index.ts create mode 100644 tgui/packages/tgui/logging.ts create mode 100644 tgui/packages/tgui/package.json create mode 100644 tgui/packages/tgui/process.ts create mode 100644 tgui/packages/tgui/renderer.ts create mode 100644 tgui/packages/tgui/routes.tsx create mode 100644 tgui/packages/tgui/sanitize.ts create mode 100644 tgui/packages/tgui/stack.ts create mode 100644 tgui/packages/tgui/styles/assets/bg-deforest.svg create mode 100644 tgui/packages/tgui/styles/base.scss create mode 100644 tgui/packages/tgui/styles/colors.scss create mode 100644 tgui/packages/tgui/styles/css-variables.scss create mode 100644 tgui/packages/tgui/styles/functions.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Accounting.scss create mode 100644 tgui/packages/tgui/styles/interfaces/AlertModal.scss create mode 100644 tgui/packages/tgui/styles/interfaces/AnomalyTower.scss create mode 100644 tgui/packages/tgui/styles/interfaces/AntagInfoHeretic.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Changelog.scss create mode 100644 tgui/packages/tgui/styles/interfaces/ColorPicker.scss create mode 100644 tgui/packages/tgui/styles/interfaces/CrewManifest.scss create mode 100644 tgui/packages/tgui/styles/interfaces/DetectiveBoard.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Emojipedia.scss create mode 100644 tgui/packages/tgui/styles/interfaces/ExperimentConfigure.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Fabricator.scss create mode 100644 tgui/packages/tgui/styles/interfaces/HellishRunes.scss create mode 100644 tgui/packages/tgui/styles/interfaces/HotKeysHelp.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Hypertorus.scss create mode 100644 tgui/packages/tgui/styles/interfaces/IntegratedCircuit.scss create mode 100644 tgui/packages/tgui/styles/interfaces/LibraryAdmin.scss create mode 100644 tgui/packages/tgui/styles/interfaces/LibraryComputer.scss create mode 100644 tgui/packages/tgui/styles/interfaces/ListInput.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Mecha.scss create mode 100644 tgui/packages/tgui/styles/interfaces/NtosMessenger.scss create mode 100644 tgui/packages/tgui/styles/interfaces/NtosNotepad.scss create mode 100644 tgui/packages/tgui/styles/interfaces/NuclearBomb.scss create mode 100644 tgui/packages/tgui/styles/interfaces/OperatingComputer.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Orbit.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Paper.scss create mode 100644 tgui/packages/tgui/styles/interfaces/PreferencesMenu.scss create mode 100644 tgui/packages/tgui/styles/interfaces/RequestManager.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Roulette.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Safe.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Techweb.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Trophycase.scss create mode 100644 tgui/packages/tgui/styles/interfaces/Uplink.scss create mode 100644 tgui/packages/tgui/styles/layouts/Layout.scss create mode 100644 tgui/packages/tgui/styles/layouts/NtosHeader.scss create mode 100644 tgui/packages/tgui/styles/layouts/NtosWindow.scss create mode 100644 tgui/packages/tgui/styles/layouts/TitleBar.scss create mode 100644 tgui/packages/tgui/styles/layouts/Window.scss create mode 100644 tgui/packages/tgui/styles/main.scss create mode 100644 tgui/packages/tgui/styles/reset.scss create mode 100644 tgui/public/helpers.min.js create mode 100644 tgui/public/iframe.html create mode 100644 tgui/public/ntos-error.min.css create mode 100644 tgui/public/tgui.html delete mode 100644 tgui/reload.bat create mode 100644 tgui/rspack.config-dev.ts create mode 100644 tgui/rspack.config.ts delete mode 100644 tgui/src/.babelrc delete mode 100644 tgui/src/components/bar.ract delete mode 100644 tgui/src/components/bar.styl delete mode 100644 tgui/src/components/button.ract delete mode 100644 tgui/src/components/button.styl delete mode 100644 tgui/src/components/display.ract delete mode 100644 tgui/src/components/display.styl delete mode 100644 tgui/src/components/input.ract delete mode 100644 tgui/src/components/input.styl delete mode 100644 tgui/src/components/linegraph.ract delete mode 100644 tgui/src/components/linegraph.styl delete mode 100644 tgui/src/components/notice.ract delete mode 100644 tgui/src/components/notice.styl delete mode 100644 tgui/src/components/resize.ract delete mode 100644 tgui/src/components/resize.styl delete mode 100644 tgui/src/components/section.ract delete mode 100644 tgui/src/components/section.styl delete mode 100644 tgui/src/components/subdisplay.ract delete mode 100644 tgui/src/components/subdisplay.styl delete mode 100644 tgui/src/components/tabs.ract delete mode 100644 tgui/src/components/tabs/tab.ract delete mode 100644 tgui/src/components/titlebar.ract delete mode 100644 tgui/src/components/titlebar.styl delete mode 100644 tgui/src/components/warnings.ract delete mode 100644 tgui/src/images/nanotrasen.svg delete mode 100644 tgui/src/images/syndicate.svg delete mode 100644 tgui/src/interfaces/acclimator.ract delete mode 100644 tgui/src/interfaces/ai_airlock.ract delete mode 100644 tgui/src/interfaces/airalarm.ract delete mode 100644 tgui/src/interfaces/airalarm/back.ract delete mode 100644 tgui/src/interfaces/airalarm/modes.ract delete mode 100644 tgui/src/interfaces/airalarm/scrubbers.ract delete mode 100644 tgui/src/interfaces/airalarm/status.ract delete mode 100644 tgui/src/interfaces/airalarm/thresholds.ract delete mode 100644 tgui/src/interfaces/airalarm/vents.ract delete mode 100644 tgui/src/interfaces/airlock_electronics.ract delete mode 100644 tgui/src/interfaces/airlock_electronics.styl delete mode 100644 tgui/src/interfaces/apc.ract delete mode 100644 tgui/src/interfaces/atmos_alert.ract delete mode 100644 tgui/src/interfaces/atmos_control.ract delete mode 100644 tgui/src/interfaces/atmos_filter.ract delete mode 100644 tgui/src/interfaces/atmos_mixer.ract delete mode 100644 tgui/src/interfaces/atmos_pump.ract delete mode 100644 tgui/src/interfaces/borgopanel.ract delete mode 100644 tgui/src/interfaces/brig_timer.ract delete mode 100644 tgui/src/interfaces/bsa.ract delete mode 100644 tgui/src/interfaces/canister.ract delete mode 100644 tgui/src/interfaces/cargo.ract delete mode 100644 tgui/src/interfaces/cargo_express.ract delete mode 100644 tgui/src/interfaces/cellular_emporium.ract delete mode 100644 tgui/src/interfaces/centcom_podlauncher.ract delete mode 100644 tgui/src/interfaces/chem_dispenser.ract delete mode 100644 tgui/src/interfaces/chem_heater.ract delete mode 100644 tgui/src/interfaces/chem_master.ract delete mode 100644 tgui/src/interfaces/chem_press.ract delete mode 100644 tgui/src/interfaces/chem_splitter.ract delete mode 100644 tgui/src/interfaces/chem_synthesizer.ract delete mode 100644 tgui/src/interfaces/chemical_filter.ract delete mode 100644 tgui/src/interfaces/codex_gigas.ract delete mode 100644 tgui/src/interfaces/computer_fabricator.ract delete mode 100644 tgui/src/interfaces/crayon.ract delete mode 100644 tgui/src/interfaces/crew.ract delete mode 100644 tgui/src/interfaces/cryo.ract delete mode 100644 tgui/src/interfaces/disposal_unit.ract delete mode 100644 tgui/src/interfaces/dna_vault.ract delete mode 100644 tgui/src/interfaces/eightball.ract delete mode 100644 tgui/src/interfaces/emergency_shuttle_console.ract delete mode 100644 tgui/src/interfaces/engraved_message.ract delete mode 100644 tgui/src/interfaces/error.ract delete mode 100644 tgui/src/interfaces/exonet_node.ract delete mode 100644 tgui/src/interfaces/gps.ract delete mode 100644 tgui/src/interfaces/gulag_console.ract delete mode 100644 tgui/src/interfaces/gulag_item_reclaimer.ract delete mode 100644 tgui/src/interfaces/holodeck.ract delete mode 100644 tgui/src/interfaces/implantchair.ract delete mode 100644 tgui/src/interfaces/intellicard.ract delete mode 100644 tgui/src/interfaces/keycard_auth.ract delete mode 100644 tgui/src/interfaces/labor_claim_console.ract delete mode 100644 tgui/src/interfaces/language_menu.ract delete mode 100644 tgui/src/interfaces/launchpad_console.ract delete mode 100644 tgui/src/interfaces/launchpad_remote.ract delete mode 100644 tgui/src/interfaces/mech_bay_power_console.ract delete mode 100644 tgui/src/interfaces/medical_kiosk.ract delete mode 100644 tgui/src/interfaces/mulebot.ract delete mode 100644 tgui/src/interfaces/nanite_chamber_control.ract delete mode 100644 tgui/src/interfaces/nanite_cloud_control.ract delete mode 100644 tgui/src/interfaces/nanite_comm_remote.ract delete mode 100644 tgui/src/interfaces/nanite_program_hub.ract delete mode 100644 tgui/src/interfaces/nanite_programmer.ract delete mode 100644 tgui/src/interfaces/nanite_remote.ract delete mode 100644 tgui/src/interfaces/notificationpanel.ract delete mode 100644 tgui/src/interfaces/ntnet_relay.ract delete mode 100644 tgui/src/interfaces/ntos_ai_restorer.ract delete mode 100644 tgui/src/interfaces/ntos_card.ract delete mode 100644 tgui/src/interfaces/ntos_configuration.ract delete mode 100644 tgui/src/interfaces/ntos_file_manager.ract delete mode 100644 tgui/src/interfaces/ntos_main.ract delete mode 100644 tgui/src/interfaces/ntos_net_chat.ract delete mode 100644 tgui/src/interfaces/ntos_net_dos.ract delete mode 100644 tgui/src/interfaces/ntos_net_downloader.ract delete mode 100644 tgui/src/interfaces/ntos_net_monitor.ract delete mode 100644 tgui/src/interfaces/ntos_net_transfer.ract delete mode 100644 tgui/src/interfaces/ntos_power_monitor.ract delete mode 100644 tgui/src/interfaces/ntos_revelation.ract delete mode 100644 tgui/src/interfaces/ntos_station_alert.ract delete mode 100644 tgui/src/interfaces/ntos_supermatter_monitor.ract delete mode 100644 tgui/src/interfaces/ntosheader.ract delete mode 100644 tgui/src/interfaces/nuclear_bomb.ract delete mode 100644 tgui/src/interfaces/operating_computer.ract delete mode 100644 tgui/src/interfaces/ore_redemption_machine.ract delete mode 100644 tgui/src/interfaces/pandemic.ract delete mode 100644 tgui/src/interfaces/personal_crafting.ract delete mode 100644 tgui/src/interfaces/portable_generator.ract delete mode 100644 tgui/src/interfaces/portable_pump.ract delete mode 100644 tgui/src/interfaces/portable_scrubber.ract delete mode 100644 tgui/src/interfaces/power_monitor.ract delete mode 100644 tgui/src/interfaces/radio.ract delete mode 100644 tgui/src/interfaces/rdconsole.ract delete mode 100644 tgui/src/interfaces/rdconsole/circuit.ract delete mode 100644 tgui/src/interfaces/rdconsole/designview.ract delete mode 100644 tgui/src/interfaces/rdconsole/destruct.ract delete mode 100644 tgui/src/interfaces/rdconsole/diskopsdesign.ract delete mode 100644 tgui/src/interfaces/rdconsole/diskopstech.ract delete mode 100644 tgui/src/interfaces/rdconsole/nodeview.ract delete mode 100644 tgui/src/interfaces/rdconsole/protolathe.ract delete mode 100644 tgui/src/interfaces/rdconsole/rdheader.ract delete mode 100644 tgui/src/interfaces/rdconsole/settings.ract delete mode 100644 tgui/src/interfaces/rdconsole/techweb.ract delete mode 100644 tgui/src/interfaces/reaction_chamber.ract delete mode 100644 tgui/src/interfaces/roulette.ract delete mode 100644 tgui/src/interfaces/roulette.styl delete mode 100644 tgui/src/interfaces/rpd.ract delete mode 100644 tgui/src/interfaces/sat_control.ract delete mode 100644 tgui/src/interfaces/scanner_gate.ract delete mode 100644 tgui/src/interfaces/scrubbing_types.ract delete mode 100644 tgui/src/interfaces/shuttle_manipulator.ract delete mode 100644 tgui/src/interfaces/shuttle_manipulator/modification.ract delete mode 100644 tgui/src/interfaces/shuttle_manipulator/status.ract delete mode 100644 tgui/src/interfaces/shuttle_manipulator/templates.ract delete mode 100644 tgui/src/interfaces/sleeper.ract delete mode 100644 tgui/src/interfaces/slime_swap_body.ract delete mode 100644 tgui/src/interfaces/smartvend.ract delete mode 100644 tgui/src/interfaces/smes.ract delete mode 100644 tgui/src/interfaces/smoke_machine.ract delete mode 100644 tgui/src/interfaces/solar_control.ract delete mode 100644 tgui/src/interfaces/space_heater.ract delete mode 100644 tgui/src/interfaces/spawners_menu.ract delete mode 100644 tgui/src/interfaces/station_alert.ract delete mode 100644 tgui/src/interfaces/suit_storage_unit.ract delete mode 100644 tgui/src/interfaces/synd_contract.ract delete mode 100644 tgui/src/interfaces/synthesizer.ract delete mode 100644 tgui/src/interfaces/tank_dispenser.ract delete mode 100644 tgui/src/interfaces/tanks.ract delete mode 100644 tgui/src/interfaces/thermomachine.ract delete mode 100644 tgui/src/interfaces/turbine_computer.ract delete mode 100644 tgui/src/interfaces/uplink.ract delete mode 100644 tgui/src/interfaces/vault_controller.ract delete mode 100644 tgui/src/interfaces/wires.ract delete mode 100644 tgui/src/styles/clockwork.styl delete mode 100644 tgui/src/styles/nanotrasen.styl delete mode 100644 tgui/src/styles/syndicate.styl delete mode 100644 tgui/src/tgui.js delete mode 100644 tgui/src/tgui.ract delete mode 100644 tgui/src/tgui.styl delete mode 100644 tgui/src/util/byond.js delete mode 100644 tgui/src/util/colors.styl delete mode 100644 tgui/src/util/constants.js delete mode 100644 tgui/src/util/dragresize.js delete mode 100644 tgui/src/util/filter.js delete mode 100644 tgui/src/util/math.js delete mode 100644 tgui/src/util/misc.styl delete mode 100644 tgui/src/util/text.js delete mode 100644 tgui/src/util/text.styl delete mode 100644 tgui/src/util/tooltip.styl create mode 100644 tgui/tsconfig.json diff --git a/tgui-next/.editorconfig b/tgui-next/.editorconfig deleted file mode 100644 index 33092d4928a..00000000000 --- a/tgui-next/.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -# http://editorconfig.org -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -max_line_length = 80 diff --git a/tgui-next/.eslintignore b/tgui-next/.eslintignore deleted file mode 100644 index 010416b9e88..00000000000 --- a/tgui-next/.eslintignore +++ /dev/null @@ -1,6 +0,0 @@ -/**/node_modules -/**/*.bundle.* -/**/*.chunk.* -/**/*.hot-update.* -/packages/inferno/** -/packages/tgui/public/shim-*.js diff --git a/tgui-next/.eslintrc.yml b/tgui-next/.eslintrc.yml deleted file mode 100644 index 196fb34f7fa..00000000000 --- a/tgui-next/.eslintrc.yml +++ /dev/null @@ -1,715 +0,0 @@ -parser: babel-eslint -parserOptions: - ecmaVersion: 2019 - sourceType: module - ecmaFeatures: - jsx: true -env: - es6: true - browser: true - node: true -plugins: - - react -settings: - react: - version: '16.10' -rules: - - ## Possible Errors - ## ---------------------------------------- - - ## Enforce “for” loop update clause moving the counter in the right direction. - # for-direction: error - ## Enforce return statements in getters - # getter-return: error - ## Disallow using an async function as a Promise executor - no-async-promise-executor: error - ## Disallow await inside of loops - # no-await-in-loop: error - ## Disallow comparing against -0 - # no-compare-neg-zero: error - ## Disallow assignment operators in conditional expressions - no-cond-assign: error - ## Disallow the use of console - # no-console: error - ## Disallow constant expressions in conditions - # no-constant-condition: error - ## Disallow control characters in regular expressions - # no-control-regex: error - ## Disallow the use of debugger - no-debugger: error - ## Disallow duplicate arguments in function definitions - no-dupe-args: error - ## Disallow duplicate keys in object literals - no-dupe-keys: error - ## Disallow duplicate case labels - no-duplicate-case: error - ## Disallow empty block statements - # no-empty: error - ## Disallow empty character classes in regular expressions - no-empty-character-class: error - ## Disallow reassigning exceptions in catch clauses - no-ex-assign: error - ## Disallow unnecessary boolean casts - no-extra-boolean-cast: error - ## Disallow unnecessary parentheses - # no-extra-parens: warn - ## Disallow unnecessary semicolons - no-extra-semi: error - ## Disallow reassigning function declarations - no-func-assign: error - ## Disallow assigning to imported bindings - no-import-assign: error - ## Disallow variable or function declarations in nested blocks - no-inner-declarations: error - ## Disallow invalid regular expression strings in RegExp constructors - no-invalid-regexp: error - ## Disallow irregular whitespace - no-irregular-whitespace: error - ## Disallow characters which are made with multiple code points in character class syntax - no-misleading-character-class: error - ## Disallow calling global object properties as functions - no-obj-calls: error - ## Disallow calling some Object.prototype methods directly on objects - no-prototype-builtins: error - ## Disallow multiple spaces in regular expressions - no-regex-spaces: error - ## Disallow sparse arrays - no-sparse-arrays: error - ## Disallow template literal placeholder syntax in regular strings - no-template-curly-in-string: error - ## Disallow confusing multiline expressions - no-unexpected-multiline: error - ## Disallow unreachable code after return, throw, continue, and break statements - # no-unreachable: warn - ## Disallow control flow statements in finally blocks - no-unsafe-finally: error - ## Disallow negating the left operand of relational operators - no-unsafe-negation: error - ## Disallow assignments that can lead to race conditions due to usage of await or yield - # require-atomic-updates: error - ## Require calls to isNaN() when checking for NaN - use-isnan: error - ## Enforce comparing typeof expressions against valid strings - valid-typeof: error - - ## Best practices - ## ---------------------------------------- - ## Enforce getter and setter pairs in objects and classes - # accessor-pairs: error - ## Enforce return statements in callbacks of array methods - # array-callback-return: error - ## Enforce the use of variables within the scope they are defined - # block-scoped-var: error - ## Enforce that class methods utilize this - # class-methods-use-this: error - ## Enforce a maximum cyclomatic complexity allowed in a program - complexity: [error, { max: 50 }] - ## Require return statements to either always or never specify values - # consistent-return: error - ## Enforce consistent brace style for all control statements - curly: [error, all] - ## Require default cases in switch statements - # default-case: error - ## Enforce default parameters to be last - # default-param-last: error - ## Enforce consistent newlines before and after dots - dot-location: [error, property] - ## Enforce dot notation whenever possible - # dot-notation: error - ## Require the use of === and !== - eqeqeq: [error, always] - ## Require for-in loops to include an if statement - # guard-for-in: error - ## Enforce a maximum number of classes per file - # max-classes-per-file: error - ## Disallow the use of alert, confirm, and prompt - # no-alert: error - ## Disallow the use of arguments.requester or arguments.callee - # no-requester: error - ## Disallow lexical declarations in case clauses - # no-case-declarations: error - ## Disallow division operators explicitly at the beginning of regular expressions - # no-div-regex: error - ## Disallow else blocks after return statements in if statements - # no-else-return: error - ## Disallow empty functions - # no-empty-function: error - ## Disallow empty destructuring patterns - no-empty-pattern: error - ## Disallow null comparisons without type-checking operators - # no-eq-null: error - ## Disallow the use of eval() - # no-eval: error - ## Disallow extending native types - # no-extend-native: error - ## Disallow unnecessary calls to .bind() - # no-extra-bind: error - ## Disallow unnecessary labels - # no-extra-label: error - ## Disallow fallthrough of case statements - # no-fallthrough: error - ## Disallow leading or trailing decimal points in numeric literals - # no-floating-decimal: error - ## Disallow assignments to native objects or read-only global variables - # no-global-assign: error - ## Disallow shorthand type conversions - # no-implicit-coercion: error - ## Disallow variable and function declarations in the global scope - # no-implicit-globals: error - ## Disallow the use of eval()-like methods - # no-implied-eval: error - ## Disallow this keywords outside of classes or class-like objects - # no-invalid-this: error - ## Disallow the use of the __iterator__ property - # no-iterator: error - ## Disallow labeled statements - # no-labels: error - ## Disallow unnecessary nested blocks - # no-lone-blocks: error - ## Disallow function declarations that contain unsafe references inside loop statements - # no-loop-func: error - ## Disallow magic numbers - # no-magic-numbers: error - ## Disallow multiple spaces - no-multi-spaces: warn - ## Disallow multiline strings - # no-multi-str: error - ## Disallow new operators outside of assignments or comparisons - # no-new: error - ## Disallow new operators with the Function object - # no-new-func: error - ## Disallow new operators with the String, Number, and Boolean objects - # no-new-wrappers: error - ## Disallow octal literals - no-octal: error - ## Disallow octal escape sequences in string literals - no-octal-escape: error - ## Disallow reassigning function parameters - # no-param-reassign: error - ## Disallow the use of the __proto__ property - # no-proto: error - ## Disallow variable redeclaration - # no-redeclare: error - ## Disallow certain properties on certain objects - # no-restricted-properties: error - ## Disallow assignment operators in return statements - no-return-assign: error - ## Disallow unnecessary return await - # no-return-await: error - ## Disallow javascript: urls - # no-script-url: error - ## Disallow assignments where both sides are exactly the same - no-self-assign: error - ## Disallow comparisons where both sides are exactly the same - # no-self-compare: error - ## Disallow comma operators - no-sequences: error - ## Disallow throwing literals as exceptions - # no-throw-literal: error - ## Disallow unmodified loop conditions - # no-unmodified-loop-condition: error - ## Disallow unused expressions - # no-unused-expressions: error - ## Disallow unused labels - no-unused-labels: warn - ## Disallow unnecessary calls to .call() and .apply() - # no-useless-call: error - ## Disallow unnecessary catch clauses - # no-useless-catch: error - ## Disallow unnecessary concatenation of literals or template literals - # no-useless-concat: error - ## Disallow unnecessary escape characters - no-useless-escape: warn - ## Disallow redundant return statements - # no-useless-return: error - ## Disallow void operators - # no-void: error - ## Disallow specified warning terms in comments - # no-warning-comments: error - ## Disallow with statements - no-with: error - ## Enforce using named capture group in regular expression - # prefer-named-capture-group: error - ## Require using Error objects as Promise rejection reasons - # prefer-promise-reject-errors: error - ## Disallow use of the RegExp constructor in favor of regular expression literals - # prefer-regex-literals: error - ## Enforce the consistent use of the radix argument when using parseInt() - radix: error - ## Disallow async functions which have no await expression - # require-await: error - ## Enforce the use of u flag on RegExp - # require-unicode-regexp: error - ## Require var declarations be placed at the top of their containing scope - # vars-on-top: error - ## Require parentheses around immediate function invocations - # wrap-iife: error - ## Require or disallow “Yoda” conditions - # yoda: error - - ## Strict mode - ## ---------------------------------------- - ## Require or disallow strict mode directives - strict: error - - ## Variables - ## ---------------------------------------- - ## Require or disallow initialization in variable declarations - # init-declarations: error - ## Disallow deleting variables - no-delete-var: error - ## Disallow labels that share a name with a variable - # no-label-var: error - ## Disallow specified global variables - # no-restricted-globals: error - ## Disallow variable declarations from shadowing variables declared in - ## the outer scope - # no-shadow: error - ## Disallow identifiers from shadowing restricted names - no-shadow-restricted-names: error - ## Disallow the use of undeclared variables unless mentioned - ## in /*global*/ comments - no-undef: error - ## Disallow initializing variables to undefined - no-undef-init: error - ## Disallow the use of undefined as an identifier - # no-undefined: error - ## Disallow unused variables - # no-unused-vars: error - ## Disallow the use of variables before they are defined - # no-use-before-define: error - - ## Code style - ## ---------------------------------------- - ## Enforce linebreaks after opening and before closing array brackets - array-bracket-newline: [error, consistent] - ## Enforce consistent spacing inside array brackets - array-bracket-spacing: [error, never] - ## Enforce line breaks after each array element - # array-element-newline: error - ## Disallow or enforce spaces inside of blocks after opening block and before closing block - block-spacing: [error, always] - ## Enforce consistent brace style for blocks - # brace-style: [error, stroustrup, { allowSingleLine: false }] - ## Enforce camelcase naming convention - # camelcase: error - ## Enforce or disallow capitalization of the first letter of a comment - # capitalized-comments: error - ## Require or disallow trailing commas - comma-dangle: [error, always-multiline] - ## Enforce consistent spacing before and after commas - comma-spacing: [error, { before: false, after: true }] - ## Enforce consistent comma style - comma-style: [error, last] - ## Enforce consistent spacing inside computed property brackets - computed-property-spacing: [error, never] - ## Enforce consistent naming when capturing the current execution context - # consistent-this: error - ## Require or disallow newline at the end of files - # eol-last: error - ## Require or disallow spacing between function identifiers and their invocations - func-call-spacing: [error, never] - ## Require function names to match the name of the variable or property to which they are assigned - # func-name-matching: error - ## Require or disallow named function expressions - # func-names: error - ## Enforce the consistent use of either function declarations or expressions - func-style: [error, expression] - ## Enforce line breaks between arguments of a function call - # function-call-argument-newline: error - ## Enforce consistent line breaks inside function parentheses - ## NOTE: This rule does not honor a newline on opening paren. - # function-paren-newline: [error, never] - ## Disallow specified identifiers - # id-blacklist: error - ## Enforce minimum and maximum identifier lengths - # id-length: error - ## Require identifiers to match a specified regular expression - # id-match: error - ## Enforce the location of arrow function bodies - # implicit-arrow-linebreak: error - ## Enforce consistent indentation - indent: [error, 2, { SwitchCase: 1 }] - ## Enforce the consistent use of either double or single quotes in JSX attributes - jsx-quotes: [error, prefer-double] - ## Enforce consistent spacing between keys and values in object literal properties - key-spacing: [error, { beforeColon: false, afterColon: true }] - ## Enforce consistent spacing before and after keywords - keyword-spacing: [error, { before: true, after: true }] - ## Enforce position of line comments - # line-comment-position: error - ## Enforce consistent linebreak style - # linebreak-style: error - ## Require empty lines around comments - # lines-around-comment: error - ## Require or disallow an empty line between class members - # lines-between-class-members: error - ## Enforce a maximum depth that blocks can be nested - # max-depth: error - ## Enforce a maximum line length - max-len: [error, { code: 120 }] - ## Enforce a maximum number of lines per file - # max-lines: error - ## Enforce a maximum number of line of code in a function - # max-lines-per-function: error - ## Enforce a maximum depth that callbacks can be nested - # max-nested-callbacks: error - ## Enforce a maximum number of parameters in function definitions - # max-params: error - ## Enforce a maximum number of statements allowed in function blocks - # max-statements: error - ## Enforce a maximum number of statements allowed per line - # max-statements-per-line: error - ## Enforce a particular style for multiline comments - # multiline-comment-style: error - ## Enforce newlines between operands of ternary expressions - multiline-ternary: [error, always-multiline] - ## Require constructor names to begin with a capital letter - # new-cap: error - ## Enforce or disallow parentheses when invoking a constructor with no arguments - # new-parens: error - ## Require a newline after each call in a method chain - # newline-per-chained-call: error - ## Disallow Array constructors - # no-array-constructor: error - ## Disallow bitwise operators - # no-bitwise: error - ## Disallow continue statements - # no-continue: error - ## Disallow inline comments after code - # no-inline-comments: error - ## Disallow if statements as the only statement in else blocks - # no-lonely-if: error - ## Disallow mixed binary operators - # no-mixed-operators: error - ## Disallow mixed spaces and tabs for indentation - no-mixed-spaces-and-tabs: error - ## Disallow use of chained assignment expressions - # no-multi-assign: error - ## Disallow multiple empty lines - # no-multiple-empty-lines: error - ## Disallow negated conditions - # no-negated-condition: error - ## Disallow nested ternary expressions - # no-nested-ternary: error - ## Disallow Object constructors - # no-new-object: error - ## Disallow the unary operators ++ and -- - # no-plusplus: error - ## Disallow specified syntax - # no-restricted-syntax: error - ## Disallow all tabs - # no-tabs: error - ## Disallow ternary operators - # no-ternary: error - ## Disallow trailing whitespace at the end of lines - # no-trailing-spaces: error - ## Disallow dangling underscores in identifiers - # no-underscore-dangle: error - ## Disallow ternary operators when simpler alternatives exist - # no-unneeded-ternary: error - ## Disallow whitespace before properties - no-whitespace-before-property: error - ## Enforce the location of single-line statements - # nonblock-statement-body-position: error - ## Enforce consistent line breaks inside braces - # object-curly-newline: error - ## Enforce consistent spacing inside braces - # object-curly-spacing: error - ## Enforce placing object properties on separate lines - # object-property-newline: error - ## Enforce variables to be declared either together or separately in functions - # one-var: error - ## Require or disallow newlines around variable declarations - # one-var-declaration-per-line: error - ## Require or disallow assignment operator shorthand where possible - # operator-assignment: error - ## Enforce consistent linebreak style for operators - operator-linebreak: [error, before] - ## Require or disallow padding within blocks - # padded-blocks: error - ## Require or disallow padding lines between statements - # padding-line-between-statements: error - ## Disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead. - # prefer-object-spread: error - ## Require quotes around object literal property names - # quote-props: error - ## Enforce the consistent use of either backticks, double, or single quotes - # quotes: [error, single] - ## Require or disallow semicolons instead of ASI - semi: error - ## Enforce consistent spacing before and after semicolons - semi-spacing: [error, { before: false, after: true }] - ## Enforce location of semicolons - semi-style: [error, last] - ## Require object keys to be sorted - # sort-keys: error - ## Require variables within the same declaration block to be sorted - # sort-vars: error - ## Enforce consistent spacing before blocks - space-before-blocks: [error, always] - ## Enforce consistent spacing before function definition opening parenthesis - space-before-function-paren: [error, { - anonymous: always, - named: never, - asyncArrow: always, - }] - ## Enforce consistent spacing inside parentheses - space-in-parens: [error, never] - ## Require spacing around infix operators - # space-infix-ops: error - ## Enforce consistent spacing before or after unary operators - # space-unary-ops: error - ## Enforce consistent spacing after the // or /* in a comment - spaced-comment: [error, always] - ## Enforce spacing around colons of switch statements - switch-colon-spacing: [error, { before: false, after: true }] - ## Require or disallow spacing between template tags and their literals - template-tag-spacing: [error, never] - ## Require or disallow Unicode byte order mark (BOM) - # unicode-bom: [error, never] - ## Require parenthesis around regex literals - # wrap-regex: error - - ## ES6 - ## ---------------------------------------- - ## Require braces around arrow function bodies - # arrow-body-style: error - ## Require parentheses around arrow function arguments - arrow-parens: [error, as-needed] - ## Enforce consistent spacing before and after the arrow in arrow functions - arrow-spacing: [error, { before: true, after: true }] - ## Require super() calls in constructors - # constructor-super: error - ## Enforce consistent spacing around * operators in generator functions - generator-star-spacing: [error, { before: false, after: true }] - ## Disallow reassigning class members - no-class-assign: error - ## Disallow arrow functions where they could be confused with comparisons - # no-confusing-arrow: error - ## Disallow reassigning const variables - no-const-assign: error - ## Disallow duplicate class members - no-dupe-class-members: error - ## Disallow duplicate module imports - # no-duplicate-imports: error - ## Disallow new operators with the Symbol object - no-new-symbol: error - ## Disallow specified modules when loaded by import - # no-restricted-imports: error - ## Disallow this/super before calling super() in constructors - no-this-before-super: error - ## Disallow unnecessary computed property keys in object literals - # no-useless-computed-key: error - ## Disallow unnecessary constructors - # no-useless-constructor: error - ## Disallow renaming import, export, and destructured assignments to the same name - # no-useless-rename: error - ## Require let or const instead of var - no-var: error - ## Require or disallow method and property shorthand syntax for object literals - # object-shorthand: error - ## Require using arrow functions for callbacks - prefer-arrow-callback: error - ## Require const declarations for variables that are never reassigned after declared - # prefer-const: error - ## Require destructuring from arrays and/or objects - # prefer-destructuring: error - ## Disallow parseInt() and Number.parseInt() in favor of binary, octal, and hexadecimal literals - # prefer-numeric-literals: error - ## Require rest parameters instead of arguments - # prefer-rest-params: error - ## Require spread operators instead of .apply() - # prefer-spread: error - ## Require template literals instead of string concatenation - # prefer-template: error - ## Require generator functions to contain yield - # require-yield: error - ## Enforce spacing between rest and spread operators and their expressions - # rest-spread-spacing: error - ## Enforce sorted import declarations within modules - # sort-imports: error - ## Require symbol descriptions - # symbol-description: error - ## Require or disallow spacing around embedded expressions of template strings - # template-curly-spacing: error - ## Require or disallow spacing around the * in yield* expressions - yield-star-spacing: [error, { before: false, after: true }] - - ## React - ## ---------------------------------------- - ## Enforces consistent naming for boolean props - react/boolean-prop-naming: error - ## Forbid "button" element without an explicit "type" attribute - react/button-has-type: error - ## Prevent extraneous defaultProps on components - react/default-props-match-prop-types: error - ## Rule enforces consistent usage of destructuring assignment in component - # react/destructuring-assignment: [error, always, { ignoreClassFields: true }] - ## Prevent missing displayName in a React component definition - react/display-name: error - ## Forbid certain props on Components - # react/forbid-component-props: error - ## Forbid certain props on DOM Nodes - # react/forbid-dom-props: error - ## Forbid certain elements - # react/forbid-elements: error - ## Forbid certain propTypes - # react/forbid-prop-types: error - ## Forbid foreign propTypes - # react/forbid-foreign-prop-types: error - ## Prevent using this.state inside this.setState - react/no-access-state-in-setstate: error - ## Prevent using Array index in key props - # react/no-array-index-key: error - ## Prevent passing children as props - react/no-children-prop: error - ## Prevent usage of dangerous JSX properties - react/no-danger: error - ## Prevent problem with children and props.dangerouslySetInnerHTML - react/no-danger-with-children: error - ## Prevent usage of deprecated methods, including component lifecycle methods - react/no-deprecated: error - ## Prevent usage of setState in componentDidMount - react/no-did-mount-set-state: error - ## <<<<< - ## Prevent usage of setState in componentDidUpdate - react/no-did-update-set-state: error - ## Prevent direct mutation of this.state - react/no-direct-mutation-state: error - ## Prevent usage of findDOMNode - react/no-find-dom-node: error - ## Prevent usage of isMounted - react/no-is-mounted: error - ## Prevent multiple component definition per file - # react/no-multi-comp: error - ## Prevent usage of shouldComponentUpdate when extending React.PureComponent - react/no-redundant-should-component-update: error - ## Prevent usage of the return value of React.render - react/no-render-return-value: error - ## Prevent usage of setState - # react/no-set-state: error - ## Prevent common casing typos - react/no-typos: error - ## Prevent using string references in ref attribute. - react/no-string-refs: error - ## Prevent using this in stateless functional components - react/no-this-in-sfc: error - ## Prevent invalid characters from appearing in markup - react/no-unescaped-entities: error - ## Prevent usage of unknown DOM property (fixable) - react/no-unknown-property: error - ## Prevent usage of unsafe lifecycle methods - react/no-unsafe: error - ## Prevent definitions of unused prop types - react/no-unused-prop-types: error - ## Prevent definitions of unused state properties - react/no-unused-state: error - ## Prevent usage of setState in componentWillUpdate - react/no-will-update-set-state: error - ## Enforce ES5 or ES6 class for React Components - react/prefer-es6-class: error - ## Enforce that props are read-only - react/prefer-read-only-props: error - ## Enforce stateless React Components to be written as a pure function - react/prefer-stateless-function: error - ## Prevent missing props validation in a React component definition - # react/prop-types: error - ## Prevent missing React when using JSX - # react/react-in-jsx-scope: error - ## Enforce a defaultProps definition for every prop that is not a required prop - # react/require-default-props: error - ## Enforce React components to have a shouldComponentUpdate method - # react/require-optimization: error - ## Enforce ES5 or ES6 class for returning value in render function - react/require-render-return: error - ## Prevent extra closing tags for components without children (fixable) - react/self-closing-comp: error - ## Enforce component methods order (fixable) - # react/sort-comp: error - ## Enforce propTypes declarations alphabetical sorting - # react/sort-prop-types: error - ## Enforce the state initialization style to be either in a constructor or with a class property - react/state-in-constructor: error - ## Enforces where React component static properties should be positioned. - # react/static-property-placement: error - ## Enforce style prop value being an object - react/style-prop-object: error - ## Prevent void DOM elements (e.g. ,
) from receiving children - react/void-dom-elements-no-children: error - - ## JSX-specific rules - ## ---------------------------------------- - ## Enforce boolean attributes notation in JSX (fixable) - react/jsx-boolean-value: error - ## Enforce or disallow spaces inside of curly braces in JSX attributes and expressions. - # react/jsx-child-element-spacing: error - ## Validate closing bracket location in JSX (fixable) - ## NOTE: Too fucking annoying because all styles are viable - # react/jsx-closing-bracket-location: [error, { - # selfClosing: after-props, - # nonEmpty: after-props, - # }] - ## Validate closing tag location in JSX (fixable) - react/jsx-closing-tag-location: error - ## Enforce or disallow newlines inside of curly braces in JSX attributes and expressions (fixable) - react/jsx-curly-newline: error - ## Enforce or disallow spaces inside of curly braces in JSX attributes and expressions (fixable) - react/jsx-curly-spacing: error - ## Enforce or disallow spaces around equal signs in JSX attributes (fixable) - react/jsx-equals-spacing: error - ## Restrict file extensions that may contain JSX - # react/jsx-filename-extension: error - ## Enforce position of the first prop in JSX (fixable) - # react/jsx-first-prop-new-line: error - ## Enforce event handler naming conventions in JSX - react/jsx-handler-names: error - ## Validate JSX indentation (fixable) - react/jsx-indent: [error, 2] - ## Validate props indentation in JSX (fixable) - react/jsx-indent-props: [error, 2] - ## Validate JSX has key prop when in array or iterator - react/jsx-key: error - ## Validate JSX maximum depth - react/jsx-max-depth: [error, { max: 6 }] ## Generous - ## Limit maximum of props on a single line in JSX (fixable) - # react/jsx-max-props-per-line: error - ## Prevent usage of .bind() and arrow functions in JSX props - # react/jsx-no-bind: error - ## Prevent comments from being inserted as text nodes - react/jsx-no-comment-textnodes: error - ## Prevent duplicate props in JSX - react/jsx-no-duplicate-props: error - ## Prevent usage of unwrapped JSX strings - # react/jsx-no-literals: error - ## Prevent usage of unsafe target='_blank' - react/jsx-no-target-blank: error - ## Disallow undeclared variables in JSX - react/jsx-no-undef: error - ## Disallow unnecessary fragments (fixable) - react/jsx-no-useless-fragment: error - ## Limit to one expression per line in JSX - # react/jsx-one-expression-per-line: error - ## Enforce curly braces or disallow unnecessary curly braces in JSX - # react/jsx-curly-brace-presence: error - ## Enforce shorthand or standard form for React fragments - react/jsx-fragments: error - ## Enforce PascalCase for user-defined JSX components - react/jsx-pascal-case: error - ## Disallow multiple spaces between inline JSX props (fixable) - react/jsx-props-no-multi-spaces: error - ## Disallow JSX props spreading - # react/jsx-props-no-spreading: error - ## Enforce default props alphabetical sorting - # react/jsx-sort-default-props: error - ## Enforce props alphabetical sorting (fixable) - # react/jsx-sort-props: error - ## Validate whitespace in and around the JSX opening and closing brackets (fixable) - react/jsx-tag-spacing: error - ## Prevent React to be incorrectly marked as unused - react/jsx-uses-react: error - ## Prevent variables used in JSX to be incorrectly marked as unused - react/jsx-uses-vars: error - ## Prevent missing parentheses around multilines JSX (fixable) - react/jsx-wrap-multilines: error diff --git a/tgui-next/.gitattributes b/tgui-next/.gitattributes deleted file mode 100644 index 0016cc3bf67..00000000000 --- a/tgui-next/.gitattributes +++ /dev/null @@ -1,10 +0,0 @@ -* text=auto - -## Enforce text mode and LF line breaks -*.js text eol=lf -*.css text eol=lf -*.html text eol=lf -*.json text eol=lf - -## Treat bundles as binary and ignore them during conflicts -*.bundle.* binary merge=tgui-merge-bundle diff --git a/tgui-next/.gitignore b/tgui-next/.gitignore deleted file mode 100644 index 416ca3768da..00000000000 --- a/tgui-next/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -*.log -package-lock.json - -/packages/tgui/public/.tmp/**/* -/packages/tgui/public/**/*.hot-update.* -/packages/tgui/public/**/*.map diff --git a/tgui-next/README.md b/tgui-next/README.md deleted file mode 100644 index 3ee91752eb3..00000000000 --- a/tgui-next/README.md +++ /dev/null @@ -1,795 +0,0 @@ -# tgui - -## Introduction - -tgui is a robust user interface framework of /tg/station. - -tgui is very different from most UIs you will encounter in BYOND programming. -It is heavily reliant on Javascript and web technologies as opposed to DM. -If you are familiar with NanoUI (a library which can be found on almost -every other SS13 codebase), tgui should be fairly easy to pick up. - -## Learn tgui - -People come to tgui from different backgrounds and with different -learning styles. Whether you prefer a more theoretical or a practical -approach, we hope you’ll find this section helpful. - -### Practical tutorial - -If you are completely new to frontend and prefer to **learn by doing**, -start with our [practical tutorial](docs/tutorial-and-examples.md). - -### Guides - -This project uses **Inferno** - a very fast UI rendering engine with a similar -API to React. Take your time to read these guides: - -- [React guide](https://reactjs.org/docs/hello-world.html) -- [Inferno documentation](https://infernojs.org/docs/guides/components) - -highlights differences with React. - -If you were already familiar with an older, Ractive-based tgui, and want -to translate concepts between old and new tgui, read this -[interface conversion guide](docs/converting-old-tgui-interfaces.md). - -## Pre-requisites - -You will need these programs to start developing in tgui: - -- [Node v12.13+](https://nodejs.org/en/download/) -- [Yarn v1.19+](https://yarnpkg.com/en/docs/install) -- [MSys2](https://www.msys2.org/) (optional) - -> MSys2 closely replicates a unix-like environment which is necessary for -> the `bin/tgui` script to run. It comes with a robust "mintty" terminal -> emulator which is better than any standard Windows shell, it supports -> "git" out of the box (almost like Git for Windows, but better), has -> a "pacman" package manager, and you can install a text editor like "vim" -> for a full boomer experience. - -## Usage - -**For MSys2, Git Bash, WSL, Linux or macOS users:** - -First and foremost, change your directory to `tgui-next`. - -Run `bin/tgui --install-git-hooks` (optional) to install merge drivers -which will assist you in conflict resolution when rebasing your branches. - -Run one of the following: - -- `bin/tgui` - build the project in production mode. -- `bin/tgui --dev` - launch a development server. - - tgui development server provides you with incremental compilation, - hot module replacement and logging facilities in all running instances - of tgui. In short, this means that you will instantly see changes in the - game as you code it. Very useful, highly recommended. -- `bin/tgui --dev --reload` - reload byond cache once. -- `bin/tgui --dev --debug` - run server with debug logging enabled. -- `bin/tgui --dev --no-hot` - disable hot module replacement (helps when -doing development on IE8). -- `bin/tgui --lint` - show problems with the code. -- `bin/tgui --lint --fix` - auto-fix problems with the code. -- `bin/tgui --analyze` - run a bundle analyzer. -- `bin/tgui --clean` - clean up project repo. -- `bin/tgui [webpack options]` - build the project with custom webpack -options. - -**For everyone else:** - -If you haven't opened the console already, you can do that by holding -Shift and right clicking on the `tgui-next` folder, then pressing -either `Open command window here` or `Open PowerShell window here`. - -Run `yarn install` to install npm dependencies, then one of the following: - -- `yarn run build` - build the project in production mode. -- `yarn run watch` - launch a development server. -- `yarn run lint` - show problems with the code. -- `yarn run lint --fix` - auto-fix problems with the code. -- `yarn run analyze` - run a bundle analyzer. - -We also got some batch files in store, for those who don't like fiddling -with the console: - -- `bin/tgui-build.bat` - build the project in production mode. -- `bin/tgui-dev-server.bat` - launch a development server. - -> Remember to always run a full build before submitting a PR. It creates -> a compressed javascript bundle which is then referenced from DM code. -> We prefer to keep it version controlled, so that people could build the -> game just by using Dream Maker. - -## Project structure - -- `/packages` - Each folder here represents a self-contained Node module. -- `/packages/common` - Helper functions -- `/packages/tgui/index.js` - Application entry point. -- `/packages/tgui/components` - Basic UI building blocks. -- `/packages/tgui/interfaces` - Actual in-game interfaces. -Interface takes data via the `state` prop and outputs an html-like stucture, -which you can build using existing UI components. -- `/packages/tgui/routes.js` - This is where you want to register new -interfaces, otherwise they simply won't load. -- `/packages/tgui/layout.js` - A root-level component, holding the -window elements, like the titlebar, buttons, resize handlers. Calls -`routes.js` to decide which component to render. -- `/packages/tgui/styles/main.scss` - CSS entry point. -- `/packages/tgui/styles/atomic.scss` - Atomic CSS classes. -These are very simple, tiny, reusable CSS classes which you can use and -combine to change appearance of your elements. Keep them small. -- `/packages/tgui/styles/components.scss` - CSS classes which are used -in UI components, and most of the stylesheets referenced here are located -in `/packages/tgui/components`. These stylesheets closely follow the -[BEM](https://en.bem.info/methodology/) methodology. -- `/packages/tgui/styles/functions.scss` - Useful SASS functions. -Stuff like `lighten`, `darken`, `luminance` are defined here. - -## Component reference - -> Notice: This documentation might be out of date, so always check the source -> code to see the most up-to-date information. - -These are the components which you can use for interface construction. -If you have trouble finding the exact prop you need on a component, -please note, that most of these components inherit from other basic -components, such as `Box`. This component in particular provides a lot -of styling options for all components, e.g. `color` and `opacity`, thus -it is used a lot in this framework. - -There are a few important semantics you need to know about: - -- `content` prop is a synonym to a `children` prop. - - `content` is better used when your element is a self-closing tag - (like ``), and when content is long and complex. This is - a native React prop (unlike `content`), and contains all elements you - defined between the opening and the closing tag of an element. - - You should never use both on a same element. - - You should never use `children` explicitly as a prop on an element. -- Inferno supports both camelcase (`onClick`) and lowercase (`onclick`) -event names. - - Camel case names are what's called "synthetic" events, and are the - *preferred way* of handling events in React, for efficiency and - performance reasons. Please read - [Inferno Event Handling](https://infernojs.org/docs/guides/event-handling) - to understand what this is about. - - Lower case names are native browser events and should be used sparingly, - for example when you need an explicit IE8 support. **DO NOT** use - lowercase event handlers unless you really know what you are doing. - - [Button](#button) component straight up does not support lowercase event - handlers. Use the camel case `onClick` instead. - -### `AnimatedNumber` - -This component provides animations for numeric values. - -Props: - -- `value: number` - Value to animate. -- `initial: number` - Initial value to use in animation when element -first appears. If you set initial to `0` for example, number will always -animate starting from `0`, and if omitted, it will not play an initial -animation. -- `format: value => value` - Output formatter. - - Example: `value => Math.round(value)`. -- `children: (formattedValue, rawValue) => any` - Pull the animated number to -animate more complex things deeper in the DOM tree. - - Example: `(_, value) => ` - -### `BlockQuote` - -Just a block quote, just like this example in markdown: - -> Here's an example of a block quote. - -Props: - -- See inherited props: [Box](#box) - -### `Box` - -The Box component serves as a wrapper component for most of the CSS utility -needs. It creates a new DOM element, a `
` by default that can be changed -with the `as` property. Let's say you want to use a `` instead: - -```jsx - - - ); - })} -
-
- {content || null} -
- - ); - } -} - -/** - * A dummy component, which is used for carrying props for the - * tab container. - */ -export const Tab = props => null; - -Tab.defaultProps = { - __type__: TAB_MAGIC_TYPE, -}; - -Tabs.Tab = Tab; diff --git a/tgui-next/packages/tgui/components/TitleBar.js b/tgui-next/packages/tgui/components/TitleBar.js deleted file mode 100644 index c9c4eb630a4..00000000000 --- a/tgui-next/packages/tgui/components/TitleBar.js +++ /dev/null @@ -1,42 +0,0 @@ -import { classes, pureComponentHooks } from 'common/react'; -import { UI_DISABLED, UI_INTERACTIVE, UI_UPDATE } from '../constants'; -import { Icon } from './Icon'; - -const statusToColor = status => { - switch (status) { - case UI_INTERACTIVE: - return 'good'; - case UI_UPDATE: - return 'average'; - case UI_DISABLED: - default: - return 'bad'; - } -}; - -export const TitleBar = props => { - const { className, title, status, fancy, onDragStart, onClose } = props; - return ( -
- -
- {title} -
-
fancy && onDragStart(e)} /> - {!!fancy && ( -
- )} -
- ); -}; - -TitleBar.defaultHooks = pureComponentHooks; diff --git a/tgui-next/packages/tgui/components/Toast.js b/tgui-next/packages/tgui/components/Toast.js deleted file mode 100644 index d3b9d603de2..00000000000 --- a/tgui-next/packages/tgui/components/Toast.js +++ /dev/null @@ -1,57 +0,0 @@ -import { pureComponentHooks } from 'common/react'; - -export const Toast = props => { - const { content, children } = props; - return ( -
- {content} - {children} -
- ); -}; - -Toast.defaultHooks = pureComponentHooks; - -let toastTimeout; - -/** - * Shows a toast at the bottom of the screen. - * - * Takes the store's dispatch function, and text as a second argument. - */ -export const showToast = (dispatch, text) => { - if (toastTimeout) { - clearTimeout(toastTimeout); - } - toastTimeout = setTimeout(() => { - toastTimeout = undefined; - dispatch({ - type: 'hideToast', - }); - }, 5000); - dispatch({ - type: 'showToast', - payload: { text }, - }); -}; - -export const toastReducer = (state, action) => { - const { type, payload } = action; - - if (type === 'showToast') { - const { text } = payload; - return { - ...state, - toastText: text, - }; - } - - if (type === 'hideToast') { - return { - ...state, - toastText: null, - }; - } - - return state; -}; diff --git a/tgui-next/packages/tgui/components/Tooltip.js b/tgui-next/packages/tgui/components/Tooltip.js deleted file mode 100644 index c46f3c45f70..00000000000 --- a/tgui-next/packages/tgui/components/Tooltip.js +++ /dev/null @@ -1,20 +0,0 @@ -import { classes } from 'common/react'; - -export const Tooltip = props => { - const { - content, - position = 'bottom', - } = props; - // Empirically calculated length of the string, - // at which tooltip text starts to overflow. - const long = typeof content === 'string' && content.length > 35; - return ( -
- ); -}; diff --git a/tgui-next/packages/tgui/components/index.js b/tgui-next/packages/tgui/components/index.js deleted file mode 100644 index eb7fc9d01c4..00000000000 --- a/tgui-next/packages/tgui/components/index.js +++ /dev/null @@ -1,21 +0,0 @@ -export { AnimatedNumber } from './AnimatedNumber'; -export { BlockQuote } from './BlockQuote'; -export { Box } from './Box'; -export { Button } from './Button'; -export { ColorBox } from './ColorBox'; -export { Dimmer } from './Dimmer'; -export { Flex } from './Flex'; -export { Grid } from './Grid'; -export { Icon } from './Icon'; -export { Input } from './Input'; -export { LabeledList } from './LabeledList'; -export { NoticeBox } from './NoticeBox'; -export { NumberInput } from './NumberInput'; -export { ProgressBar } from './ProgressBar'; -export { Section } from './Section'; -export { Table } from './Table'; -export { Tabs } from './Tabs'; -export { TitleBar } from './TitleBar'; -export { Toast } from './Toast'; -export { Tooltip } from './Tooltip'; -export { Chart } from './Chart'; diff --git a/tgui-next/packages/tgui/constants.js b/tgui-next/packages/tgui/constants.js deleted file mode 100644 index 60b288d211a..00000000000 --- a/tgui-next/packages/tgui/constants.js +++ /dev/null @@ -1,214 +0,0 @@ -// UI states, which are mirrored from the BYOND code. -export const UI_INTERACTIVE = 2; -export const UI_UPDATE = 1; -export const UI_DISABLED = 0; -export const UI_CLOSE = -1; - -// All game related colors are stored here -export const COLORS = { - // Department colors - department: { - captain: '#c06616', - security: '#e74c3c', - medbay: '#3498db', - science: '#9b59b6', - engineering: '#f1c40f', - cargo: '#f39c12', - centcom: '#00c100', - other: '#c38312', - }, - // Damage type colors - damageType: { - oxy: '#3498db', - toxin: '#2ecc71', - burn: '#e67e22', - brute: '#e74c3c', - }, -}; - -// Colors defined in CSS -export const CSS_COLORS = [ - 'black', - 'white', - 'red', - 'orange', - 'yellow', - 'olive', - 'green', - 'teal', - 'blue', - 'violet', - 'purple', - 'pink', - 'brown', - 'grey', - 'good', - 'average', - 'bad', - 'label', -]; - -export const RADIO_CHANNELS = [ - { - name: 'Syndicate', - freq: 1213, - color: '#a52a2a', - }, - { - name: 'Red Team', - freq: 1215, - color: '#ff4444', - }, - { - name: 'Blue Team', - freq: 1217, - color: '#3434fd', - }, - { - name: 'CentCom', - freq: 1337, - color: '#2681a5', - }, - { - name: 'Supply', - freq: 1347, - color: '#b88646', - }, - { - name: 'Service', - freq: 1349, - color: '#6ca729', - }, - { - name: 'Science', - freq: 1351, - color: '#c68cfa', - }, - { - name: 'Command', - freq: 1353, - color: '#5177ff', - }, - { - name: 'Medical', - freq: 1355, - color: '#57b8f0', - }, - { - name: 'Engineering', - freq: 1357, - color: '#f37746', - }, - { - name: 'Security', - freq: 1359, - color: '#dd3535', - }, - { - name: 'AI Private', - freq: 1447, - color: '#d65d95', - }, - { - name: 'Common', - freq: 1459, - color: '#1ecc43', - }, -]; - -const GASES = [ - { - 'id': 'o2', - 'name': 'Oxygen', - 'label': 'O₂', - 'color': 'blue', - }, - { - 'id': 'n2', - 'name': 'Nitrogen', - 'label': 'N₂', - 'color': 'red', - }, - { - 'id': 'co2', - 'name': 'Carbon Dioxide', - 'label': 'CO₂', - 'color': 'grey', - }, - { - 'id': 'plasma', - 'name': 'Plasma', - 'label': 'Plasma', - 'color': 'pink', - }, - { - 'id': 'water_vapor', - 'name': 'Water Vapor', - 'label': 'H₂O', - 'color': 'grey', - }, - { - 'id': 'nob', - 'name': 'Hyper-noblium', - 'label': 'Hyper-nob', - 'color': 'teal', - }, - { - 'id': 'n2o', - 'name': 'Nitrous Oxide', - 'label': 'N₂O', - 'color': 'red', - }, - { - 'id': 'no2', - 'name': 'Nitryl', - 'label': 'NO₂', - 'color': 'brown', - }, - { - 'id': 'tritium', - 'name': 'Tritium', - 'label': 'Tritium', - 'color': 'green', - }, - { - 'id': 'bz', - 'name': 'BZ', - 'label': 'BZ', - 'color': 'purple', - }, - { - 'id': 'stim', - 'name': 'Stimulum', - 'label': 'Stimulum', - 'color': 'purple', - }, - { - 'id': 'pluox', - 'name': 'Pluoxium', - 'label': 'Pluoxium', - 'color': 'blue', - }, - { - 'id': 'miasma', - 'name': 'Miasma', - 'label': 'Miasma', - 'color': 'olive', - }, -]; - -export const getGasLabel = (gasId, fallbackValue) => { - const gasSearchString = String(gasId).toLowerCase(); - const gas = GASES.find(gas => gas.id === gasSearchString - || gas.name.toLowerCase() === gasSearchString); - return gas && gas.label - || fallbackValue - || gasId; -}; - -export const getGasColor = gasId => { - const gasSearchString = String(gasId).toLowerCase(); - const gas = GASES.find(gas => gas.id === gasSearchString - || gas.name.toLowerCase() === gasSearchString); - return gas && gas.color; -}; diff --git a/tgui-next/packages/tgui/drag.js b/tgui-next/packages/tgui/drag.js deleted file mode 100644 index b3252331806..00000000000 --- a/tgui-next/packages/tgui/drag.js +++ /dev/null @@ -1,158 +0,0 @@ -import { winset, winget } from './byond'; -import { createLogger } from './logging'; - -const logger = createLogger('drag'); - -const dragState = { - dragging: false, - resizing: false, - windowRef: undefined, - screenOffset: { x: 0, y: 0 }, - dragPointOffset: {}, - resizeMatrix: {}, - initialWindowSize: {}, -}; - -export const setupDrag = async state => { - logger.log('setting up'); - dragState.windowRef = state.config.window; - // Remove window borders - // NOTE: We are currently doing it in the open() tgui module proc, and - // this bit of code is left here just in case everything goes to shit. - // if (state.config.fancy) { - // winset(state.config.window, 'titlebar', false); - // winset(state.config.window, 'can-resize', false); - // } - // Calculate offset caused by windows taskbar - const realPosition = await winget(dragState.windowRef, 'pos'); - dragState.screenOffset = { - x: realPosition.x - window.screenX, - y: realPosition.y - window.screenY, - }; - // Constraint window position - const [relocated, safePosition] = constraintPosition(realPosition); - if (relocated) { - winset(dragState.windowRef, 'pos', - safePosition.x + ',' + safePosition.y); - } - logger.debug('current dragState', dragState); -}; - -/** - * Constraints window position to safe screen area, accounting for safe - * margins which could be a system taskbar. - */ -const constraintPosition = position => { - let { x, y } = position; - let relocated = false; - // Left - if (x < 0) { - x = 0; - relocated = true; - } - // Right - else if (x + window.innerWidth > window.screen.availWidth) { - x = window.screen.availWidth - window.innerWidth; - relocated = true; - } - // Top - if (y < 0) { - y = 0; - relocated = true; - } - // Bottom - else if (y + window.innerHeight > window.screen.availHeight) { - y = window.screen.availHeight - window.innerHeight; - relocated = true; - } - return [relocated, { x, y }]; -}; - -export const dragStartHandler = event => { - logger.log('drag start'); - dragState.dragging = true; - dragState.dragPointOffset = { - x: window.screenX - event.screenX, - y: window.screenY - event.screenY, - }; - document.addEventListener('mousemove', dragMoveHandler); - document.addEventListener('mouseup', dragEndHandler); - dragHandler(event); -}; - -export const dragMoveHandler = event => { - dragHandler(event); -}; - -export const dragEndHandler = event => { - logger.log('drag end'); - dragHandler(event); - document.removeEventListener('mousemove', dragMoveHandler); - document.removeEventListener('mouseup', dragEndHandler); - dragState.dragging = false; -}; - -const dragHandler = event => { - if (!dragState.dragging) { - return; - } - event.preventDefault(); - let x = event.screenX - + dragState.screenOffset.x - + dragState.dragPointOffset.x; - let y = event.screenY - + dragState.screenOffset.y - + dragState.dragPointOffset.y; - winset(dragState.windowRef, 'pos', x + ',' + y); -}; - -export const resizeStartHandler = (x, y) => event => { - logger.log('resize start', [x, y]); - dragState.resizing = true; - dragState.resizeMatrix = { x, y }; - dragState.dragPointOffset = { - x: window.screenX - event.screenX, - y: window.screenY - event.screenY, - }; - dragState.initialWindowSize = { - x: window.innerWidth, - y: window.innerHeight, - }; - document.addEventListener('mousemove', resizeMoveHandler); - document.addEventListener('mouseup', resizeEndHandler); - resizeHandler(event); -}; - -export const resizeMoveHandler = event => { - resizeHandler(event); -}; - -export const resizeEndHandler = event => { - logger.log('resize end'); - resizeHandler(event); - document.removeEventListener('mousemove', resizeMoveHandler); - document.removeEventListener('mouseup', resizeEndHandler); - dragState.resizing = false; -}; - -const resizeHandler = event => { - if (!dragState.resizing) { - return; - } - event.preventDefault(); - let x = dragState.initialWindowSize.x - + (event.screenX - - window.screenX - + dragState.dragPointOffset.x - + 1) - * dragState.resizeMatrix.x; - let y = dragState.initialWindowSize.y - + (event.screenY - - window.screenY - + dragState.dragPointOffset.y - + 1) - * dragState.resizeMatrix.y; - winset(dragState.windowRef, 'size', - // Sane window size values - Math.max(x, 250) + ',' + Math.max(y, 120)); -}; diff --git a/tgui-next/packages/tgui/hotkeys.js b/tgui-next/packages/tgui/hotkeys.js deleted file mode 100644 index bbe8f804eba..00000000000 --- a/tgui-next/packages/tgui/hotkeys.js +++ /dev/null @@ -1,252 +0,0 @@ -import { createLogger } from './logging'; -import { callByond, tridentVersion } from './byond'; - -const logger = createLogger('hotkeys'); - -// Key codes -export const KEY_BACKSPACE = 8; -export const KEY_TAB = 9; -export const KEY_ENTER = 13; -export const KEY_SHIFT = 16; -export const KEY_CTRL = 17; -export const KEY_ALT = 18; -export const KEY_ESCAPE = 27; -export const KEY_SPACE = 32; -export const KEY_0 = 48; -export const KEY_1 = 49; -export const KEY_2 = 50; -export const KEY_3 = 51; -export const KEY_4 = 52; -export const KEY_5 = 53; -export const KEY_6 = 54; -export const KEY_7 = 55; -export const KEY_8 = 56; -export const KEY_9 = 57; -export const KEY_A = 65; -export const KEY_B = 66; -export const KEY_C = 67; -export const KEY_D = 68; -export const KEY_E = 69; -export const KEY_F = 70; -export const KEY_G = 71; -export const KEY_H = 72; -export const KEY_I = 73; -export const KEY_J = 74; -export const KEY_K = 75; -export const KEY_L = 76; -export const KEY_M = 77; -export const KEY_N = 78; -export const KEY_O = 79; -export const KEY_P = 80; -export const KEY_Q = 81; -export const KEY_R = 82; -export const KEY_S = 83; -export const KEY_T = 84; -export const KEY_U = 85; -export const KEY_V = 86; -export const KEY_W = 87; -export const KEY_X = 88; -export const KEY_Y = 89; -export const KEY_Z = 90; -export const KEY_EQUAL = 187; -export const KEY_MINUS = 189; - -const MODIFIER_KEYS = [ - KEY_CTRL, - KEY_ALT, - KEY_SHIFT, -]; - -const NO_PASSTHROUGH_KEYS = [ - KEY_ESCAPE, - KEY_ENTER, - KEY_SPACE, - KEY_TAB, - KEY_CTRL, - KEY_SHIFT, -]; - -// Tracks the "pressed" state of keys -const keyState = {}; - -const createHotkeyString = (ctrlKey, altKey, shiftKey, keyCode) => { - let str = ''; - if (ctrlKey) { - str += 'Ctrl+'; - } - if (altKey) { - str += 'Alt+'; - } - if (shiftKey) { - str += 'Shift+'; - } - if (keyCode >= 48 && keyCode <= 90) { - str += String.fromCharCode(keyCode); - } - else { - str += '[' + keyCode + ']'; - } - return str; -}; - -/** - * Parses the event and compiles information about the keypress. - */ -const getKeyData = e => { - const keyCode = window.event ? e.which : e.keyCode; - const { ctrlKey, altKey, shiftKey } = e; - return { - keyCode, - ctrlKey, - altKey, - shiftKey, - hasModifierKeys: ctrlKey || altKey || shiftKey, - keyString: createHotkeyString(ctrlKey, altKey, shiftKey, keyCode), - }; -}; - -/** - * Keyboard passthrough logic. This allows you to keep doing things - * in game while the browser window is focused. - */ -const handlePassthrough = (e, eventType) => { - const { keyCode, keyString, ctrlKey, shiftKey } = getKeyData(e); - if (e.defaultPrevented) { - return; - } - const targetName = e.target && e.target.localName; - if (targetName === 'input' || targetName === 'textarea') { - return; - } - // NOTE: We pass through only Alt of all modifier keys, because Alt - // modifier (for toggling run/walk) is implemented very shittily - // in our codebase. We pass no other modifier keys, because they can - // be used internally as tgui hotkeys. - if (ctrlKey || shiftKey || NO_PASSTHROUGH_KEYS.includes(keyCode)) { - return; - } - // Send this keypress to BYOND - if (eventType === 'keydown' && !keyState[keyCode]) { - logger.debug('passthrough', [eventType, keyString], getKeyData(e)); - return callByond('', { __keydown: keyCode }); - } - if (eventType === 'keyup' && keyState[keyCode]) { - logger.debug('passthrough', [eventType, keyString], getKeyData(e)); - return callByond('', { __keyup: keyCode }); - } -}; - -/** - * Cleanup procedure for keyboard passthrough, which should be called - * whenever you're unloading tgui. - */ -export const releaseHeldKeys = () => { - for (let keyCode of Object.keys(keyState)) { - if (keyState[keyCode]) { - logger.log(`releasing [${keyCode}] key`); - keyState[keyCode] = false; - callByond('', { __keyup: keyCode }); - } - } -}; - -const handleHotKey = (e, eventType, dispatch) => { - if (eventType !== 'keyup') { - return; - } - const keyData = getKeyData(e); - const { - ctrlKey, - altKey, - keyCode, - hasModifierKeys, - keyString, - } = keyData; - // Dispatch a detected hotkey as a store action - if (hasModifierKeys && !MODIFIER_KEYS.includes(keyCode)) { - logger.log(keyString); - // Fun stuff - if (ctrlKey && altKey && keyCode === KEY_BACKSPACE) { - // NOTE: We need to call this in a timeout, because we need a clean - // stack in order for this to be a fatal error. - setTimeout(() => { - throw new Error( - "OOPSIE WOOPSIE!! UwU We made a fucky wucky!! A wittle" - + " fucko boingo! The code monkeys at our headquarters are" - + " working VEWY HAWD to fix this!"); - }); - } - dispatch({ - type: 'hotKey', - payload: keyData, - }); - } -}; - -/** - * Subscribe to an event when browser window has been completely - * unfocused. Conveniently fires events when the browser window - * is closed from the outside. - */ -const subscribeToLossOfFocus = listenerFn => { - let timeout; - document.addEventListener('focusout', () => { - timeout = setTimeout(listenerFn); - }); - document.addEventListener('focusin', () => { - clearTimeout(timeout); - }); - window.addEventListener('beforeunload', listenerFn); -}; - -/** - * Subscribe to keydown/keyup events with globally tracked key state. - */ -const subscribeToKeyPresses = listenerFn => { - document.addEventListener('keydown', e => { - const keyCode = window.event ? e.which : e.keyCode; - listenerFn(e, 'keydown'); - keyState[keyCode] = true; - }); - document.addEventListener('keyup', e => { - const keyCode = window.event ? e.which : e.keyCode; - listenerFn(e, 'keyup'); - keyState[keyCode] = false; - }); -}; - -// Middleware -export const hotKeyMiddleware = store => { - const { dispatch } = store; - // IE8: focusin/focusout only available on IE9+ - if (tridentVersion > 4) { - // Subscribe to key events - subscribeToKeyPresses((e, eventType) => { - handlePassthrough(e, eventType); - handleHotKey(e, eventType, dispatch); - }); - // Clean up when browser window completely loses focus - subscribeToLossOfFocus(() => { - releaseHeldKeys(); - }); - } - // Pass through store actions (do nothing) - return next => action => next(action); -}; - -// Reducer -export const hotKeyReducer = (state, action) => { - const { type, payload } = action; - if (type === 'hotKey') { - const { ctrlKey, altKey, keyCode } = payload; - // Toggle kitchen sink mode - if (ctrlKey && altKey && keyCode === KEY_EQUAL) { - return { - ...state, - showKitchenSink: !state.showKitchenSink, - }; - } - return state; - } - return state; -}; diff --git a/tgui-next/packages/tgui/index.js b/tgui-next/packages/tgui/index.js deleted file mode 100644 index f43116166c6..00000000000 --- a/tgui-next/packages/tgui/index.js +++ /dev/null @@ -1,166 +0,0 @@ -import 'core-js/es'; -import 'core-js/web/immediate'; -import 'core-js/web/queue-microtask'; -import 'core-js/web/timers'; -import 'regenerator-runtime/runtime'; -import './polyfills'; - -import { loadCSS } from 'fg-loadcss'; -import { render } from 'inferno'; -import { setupHotReloading } from 'tgui-dev-server/link/client'; -import { backendUpdate } from './backend'; -import { tridentVersion } from './byond'; -import { setupDrag } from './drag'; -import { createLogger } from './logging'; -import { getRoute } from './routes'; -import { createStore } from './store'; - -const logger = createLogger(); -const store = createStore(); -const reactRoot = document.getElementById('react-root'); - -let initialRender = true; -let handedOverToOldTgui = false; - -const renderLayout = () => { - // Short-circuit the renderer - if (handedOverToOldTgui) { - return; - } - // Mark the beginning of the render - let startedAt; - if (process.env.NODE_ENV !== 'production') { - startedAt = Date.now(); - } - try { - const state = store.getState(); - // Initial render setup - if (initialRender) { - logger.log('initial render', state); - - // ----- Old TGUI chain-loader: begin ----- - const route = getRoute(state); - // Route was not found, load old TGUI - if (!route) { - logger.info('loading old tgui'); - // Short-circuit the renderer - handedOverToOldTgui = true; - // Unsubscribe from updates - window.update = window.initialize = () => {}; - // IE8: Use a redirection method - if (tridentVersion <= 4) { - setTimeout(() => { - location.href = 'tgui-fallback.html?ref=' + window.__ref__; - }, 10); - return; - } - // Inject current state into the data holder - const holder = document.getElementById('data'); - holder.textContent = JSON.stringify(state); - // Load old TGUI by injecting new scripts - loadCSS('v4shim.css'); - loadCSS('tgui.css'); - const head = document.getElementsByTagName('head')[0]; - const script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = 'tgui.js'; - head.appendChild(script); - // Bail - return; - } - // ----- Old TGUI chain-loader: end ----- - - // Setup dragging - setupDrag(state); - } - // Start rendering - const { Layout } = require('./layout'); - const element = ; - render(element, reactRoot); - } - catch (err) { - logger.error('rendering error', err); - } - // Report rendering time - if (process.env.NODE_ENV !== 'production') { - const finishedAt = Date.now(); - const diff = finishedAt - startedAt; - const diffFrames = (diff / 16.6667).toFixed(2); - logger.debug(`rendered in ${diff}ms (${diffFrames} frames)`); - if (initialRender) { - const diff = finishedAt - window.__inception__; - const diffFrames = (diff / 16.6667).toFixed(2); - logger.log(`fully loaded in ${diff}ms (${diffFrames} frames)`); - } - } - if (initialRender) { - initialRender = false; - } -}; - -// Parse JSON and report all abnormal JSON strings coming from BYOND -const parseStateJson = json => { - let reviver = (key, value) => { - if (typeof value === 'object' && value !== null) { - if (value.__number__) { - return parseFloat(value.__number__); - } - } - return value; - }; - // IE8: No reviver for you! - // See: https://stackoverflow.com/questions/1288962 - if (tridentVersion <= 4) { - reviver = undefined; - } - try { - return JSON.parse(json, reviver); - } - catch (err) { - logger.log(err); - logger.log('What we got:', json); - throw err; - } -}; - -const setupApp = () => { - // Subscribe for redux state updates - store.subscribe(() => { - renderLayout(); - }); - - // Subscribe for bankend updates - window.update = window.initialize = stateJson => { - const state = parseStateJson(stateJson); - // Backend update dispatches a store action - store.dispatch(backendUpdate(state)); - }; - - // Enable hot module reloading - if (module.hot) { - setupHotReloading(); - module.hot.accept(['./layout', './routes'], () => { - renderLayout(); - }); - } - - // Process the early update queue - while (true) { - let stateJson = window.__updateQueue__.shift(); - if (!stateJson) { - break; - } - window.update(stateJson); - } - - // Dynamically load font-awesome from browser's cache - loadCSS('font-awesome.css'); -}; - -// IE8: Wait for DOM to properly load -if (tridentVersion <= 4 && document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', setupApp); -} -else { - setupApp(); -} diff --git a/tgui-next/packages/tgui/interfaces/Achievements.js b/tgui-next/packages/tgui/interfaces/Achievements.js deleted file mode 100644 index 1ed2a1ce776..00000000000 --- a/tgui-next/packages/tgui/interfaces/Achievements.js +++ /dev/null @@ -1,37 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Box, Tabs } from '../components'; - -export const Achievements = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( - - {data.categories.map(category => ( - - - {data.achievements - .filter(x => x.category === category) - .map(achievement => ( - - - - - -

{achievement.name}

- {achievement.desc} - - - - ))} - -
- ))} -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AiAirlock.js b/tgui-next/packages/tgui/interfaces/AiAirlock.js deleted file mode 100644 index 5a8d9cc0f75..00000000000 --- a/tgui-next/packages/tgui/interfaces/AiAirlock.js +++ /dev/null @@ -1,198 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Button, LabeledList, Section } from '../components'; - -export const AiAirlock = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const dangerMap = { - 2: { - color: 'good', - localStatusText: 'Offline', - }, - 1: { - color: 'average', - localStatusText: 'Caution', - }, - 0: { - color: 'bad', - localStatusText: 'Optimal', - }, - }; - const statusMain = dangerMap[data.power.main] || dangerMap[0]; - const statusBackup = dangerMap[data.power.backup] || dangerMap[0]; - const statusElectrify = dangerMap[data.shock] || dangerMap[0]; - return ( - -
- - act(ref, 'disrupt-main')} /> - )}> - {data.power.main ? 'Online' : 'Offline'} - {' '} - {(!data.wires.main_1 || !data.wires.main_2) - && '[Wires have been cut!]' - || (data.power.main_timeleft > 0 - && `[${data.power.main_timeleft}s]`)} - - act(ref, 'disrupt-backup')} /> - )}> - {data.power.backup ? 'Online' : 'Offline'} - {' '} - {(!data.wires.backup_1 || !data.wires.backup_2) - && '[Wires have been cut!]' - || (data.power.backup_timeleft > 0 - && `[${data.power.backup_timeleft}s]`)} - - -
-
- - act(ref, 'idscan-toggle')} /> - )}> - {!data.wires.id_scanner && '[Wires have been cut!]'} - - act(ref, 'emergency-toggle')} /> - )} /> - - act(ref, 'bolt-toggle')} /> - )}> - {!data.wires.bolts && '[Wires have been cut!]'} - - act(ref, 'light-toggle')} /> - )}> - {!data.wires.lights && '[Wires have been cut!]'} - - act(ref, 'safe-toggle')} /> - )}> - {!data.wires.safe && '[Wires have been cut!]'} - - act(ref, 'speed-toggle')} /> - )}> - {!data.wires.timing && '[Wires have been cut!]'} - - - act(ref, 'open-close')} /> - )}> - {!!(data.locked || data.welded) && ( - - [Door is {data.locked ? 'bolted' : ''} - {(data.locked && data.welded) ? ' and ' : ''} - {data.welded ? 'welded' : ''}!] - - )} - - -
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AirAlarm.js b/tgui-next/packages/tgui/interfaces/AirAlarm.js deleted file mode 100644 index 801dd56cc66..00000000000 --- a/tgui-next/packages/tgui/interfaces/AirAlarm.js +++ /dev/null @@ -1,462 +0,0 @@ -import { toFixed } from 'common/math'; -import { decodeHtmlEntities } from 'common/string'; -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Box, Button, LabeledList, NumberInput, Section } from '../components'; -import { getGasLabel } from '../constants'; -import { createLogger } from '../logging'; -import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox'; - -const logger = createLogger('AirAlarm'); - -export const AirAlarm = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const locked = data.locked && !data.siliconUser; - return ( - - act(ref, 'lock')} /> - - {!locked && ( - - )} - - ); -}; - -const AirAlarmStatus = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const entries = data.environment_data || []; - const dangerMap = { - 0: { - color: 'good', - localStatusText: 'Optimal', - }, - 1: { - color: 'average', - localStatusText: 'Caution', - }, - 2: { - color: 'bad', - localStatusText: 'Danger (Internals Required)', - }, - }; - const localStatus = dangerMap[data.danger_level] || dangerMap[0]; - return ( -
- - {entries.length > 0 && ( - - {entries.map(entry => { - const status = dangerMap[entry.danger_level] || dangerMap[0]; - return ( - - {toFixed(entry.value, 2)}{entry.unit} - - ); - })} - - {localStatus.localStatusText} - - - {data.atmos_alarm && 'Atmosphere Alarm' - || data.fire_alarm && 'Fire Alarm' - || 'Nominal'} - - - ) || ( - - Cannot obtain air sample for analysis. - - )} - {!!data.emagged && ( - - Safety measures offline. Device may exhibit abnormal behavior. - - )} - -
- ); -}; - -const AIR_ALARM_ROUTES = { - home: { - title: 'Air Controls', - component: () => AirAlarmControlHome, - }, - vents: { - title: 'Vent Controls', - component: () => AirAlarmControlVents, - }, - scrubbers: { - title: 'Scrubber Controls', - component: () => AirAlarmControlScrubbers, - }, - modes: { - title: 'Operating Mode', - component: () => AirAlarmControlModes, - }, - thresholds: { - title: 'Alarm Thresholds', - component: () => AirAlarmControlThresholds, - }, -}; - -const AirAlarmControl = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const route = AIR_ALARM_ROUTES[config.screen] || AIR_ALARM_ROUTES.home; - const Component = route.component(); - return ( -
act(ref, 'tgui:view', { - screen: 'home', - })} /> - )}> - -
- ); -}; - - -// Home screen -// -------------------------------------------------------- - -const AirAlarmControlHome = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( - - - ))} - - )} - {!condi && ( - this.setState({ - pillAmount: value, - })} - onCreate={() => act(ref, 'create', { - type: 'pill', - amount: pillAmount, - volume: 'auto', - })} /> - )} - {!condi && ( - this.setState({ - patchAmount: value, - })} - onCreate={() => act(ref, 'create', { - type: 'patch', - amount: patchAmount, - volume: 'auto', - })} /> - )} - {!condi && ( - this.setState({ - bottleAmount: value, - })} - onCreate={() => act(ref, 'create', { - type: 'bottle', - amount: bottleAmount, - volume: 'auto', - })} /> - )} - {!!condi && ( - this.setState({ - packAmount: value, - })} - onCreate={() => act(ref, 'create', { - type: 'condimentPack', - amount: packAmount, - volume: 'auto', - })} /> - )} - {!!condi && ( - this.setState({ - bottleAmount: value, - })} - onCreate={() => act(ref, 'create', { - type: 'condimentBottle', - amount: bottleAmount, - volume: 'auto', - })} /> - )} - - ); - } -} - -const AnalysisResults = props => { - const { state } = props; - const { ref } = state.config; - const { analyzeVars } = state.data; - return ( -
act(ref, 'goScreen', { - screen: 'home', - })} /> - )}> - - - {analyzeVars.name} - - - {analyzeVars.state} - - - - {analyzeVars.color} - - - {analyzeVars.description} - - - {analyzeVars.metaRate} u/minute - - - {analyzeVars.overD} - - - {analyzeVars.addicD} - - -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ChemPress.js b/tgui-next/packages/tgui/interfaces/ChemPress.js deleted file mode 100644 index 491c64e091b..00000000000 --- a/tgui-next/packages/tgui/interfaces/ChemPress.js +++ /dev/null @@ -1,54 +0,0 @@ -import { act } from '../byond'; -import { Box, Button, LabeledList, Section } from '../components'; -import { NumberInput } from '../components/NumberInput'; - -export const ChemPress = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - pill_size, - pill_name, - pill_style, - pill_styles = [], - } = data; - return ( -
- - - act(ref, 'change_pill_size', {volume: value})} - /> - - - - ))} - - -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ChemSplitter.js b/tgui-next/packages/tgui/interfaces/ChemSplitter.js deleted file mode 100644 index 336c59f407e..00000000000 --- a/tgui-next/packages/tgui/interfaces/ChemSplitter.js +++ /dev/null @@ -1,47 +0,0 @@ -import { act } from '../byond'; -import { LabeledList, Section } from '../components'; -import { NumberInput } from '../components/NumberInput'; -import { toFixed } from 'common/math'; - -export const ChemSplitter = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - straight, - side, - max_transfer, - } = data; - return ( -
- - - toFixed(value, 2)} - step={0.05} - stepPixelSize={4} - onChange={(e, value) => act(ref, "set_amount", {target: "straight", amount: value})} - /> - - - toFixed(value, 2)} - step={0.05} - stepPixelSize={4} - onChange={(e, value) => act(ref, "set_amount", {target: "side", amount: value})} - /> - - -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ChemSynthesizer.js b/tgui-next/packages/tgui/interfaces/ChemSynthesizer.js deleted file mode 100644 index ae922bd4d2a..00000000000 --- a/tgui-next/packages/tgui/interfaces/ChemSynthesizer.js +++ /dev/null @@ -1,42 +0,0 @@ -import { toFixed } from 'common/math'; -import { act } from '../byond'; -import { Box, Button, Section } from '../components'; - -export const ChemSynthesizer = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - amount, - current_reagent, - chemicals = [], - possible_amounts = [], - } = data; - return ( -
- - {possible_amounts.map(possible_amount => ( -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/CodexGigas.js b/tgui-next/packages/tgui/interfaces/CodexGigas.js deleted file mode 100644 index eba22975196..00000000000 --- a/tgui-next/packages/tgui/interfaces/CodexGigas.js +++ /dev/null @@ -1,105 +0,0 @@ -import { act } from '../byond'; -import { Button, LabeledList, Section } from '../components'; - -// TODO: refactor the backend of this it's a trainwreck -export const CodexGigas = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const prefixes = [ - "Dark", - "Hellish", - "Fallen", - "Fiery", - "Sinful", - "Blood", - "Fluffy", - ]; - const titles = [ - "Lord", - "Prelate", - "Count", - "Viscount", - "Vizier", - "Elder", - "Adept", - ]; - const names = [ - "hal", - "ve", - "odr", - "neit", - "ci", - "quon", - "mya", - "folth", - "wren", - "geyr", - "hil", - "niet", - "twou", - "phi", - "coa", - ]; - const suffixes = [ - "the Red", - "the Soulless", - "the Master", - "the Lord of all things", - "Jr.", - ]; - return ( -
- {data.name} - - - {prefixes.map(prefix => ( -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ComputerFabricator.js b/tgui-next/packages/tgui/interfaces/ComputerFabricator.js deleted file mode 100644 index d9e6f328caf..00000000000 --- a/tgui-next/packages/tgui/interfaces/ComputerFabricator.js +++ /dev/null @@ -1,406 +0,0 @@ -import { multiline } from 'common/string'; -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Box, Button, Grid, Section, Table, Tooltip } from '../components'; - -export const ComputerFabricator = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( - -
- Your perfect device, only three steps away... -
- {data.state !== 0 && ( - - )} /> - - K - - - - - - )} -
- - {programs.map(program => ( - - -
-
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/NtosSupermatterMonitor.js b/tgui-next/packages/tgui/interfaces/NtosSupermatterMonitor.js deleted file mode 100644 index 3fb9aeb66d0..00000000000 --- a/tgui-next/packages/tgui/interfaces/NtosSupermatterMonitor.js +++ /dev/null @@ -1,179 +0,0 @@ -import { sortBy } from 'common/collections'; -import { flow } from 'common/fp'; -import { toFixed } from 'common/math'; -import { act } from '../byond'; -import { Box, Button, Flex, LabeledList, ProgressBar, Section, Table } from '../components'; -import { getGasColor, getGasLabel } from '../constants'; - -const logScale = value => Math.log2(16 + Math.max(0, value)) - 4; - -export const NtosSupermatterMonitor = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - active, - SM_integrity, - SM_power, - SM_ambienttemp, - SM_ambientpressure, - } = data; - if (!active) { - return ( - - ); - } - const gases = flow([ - gases => gases.filter(gas => gas.amount >= 0.01), - sortBy(gas => -gas.amount), - ])(data.gases || []); - const gasMaxAmount = Math.max(1, ...gases.map(gas => gas.amount)); - return ( - - -
- - - - - - - {toFixed(SM_power) + ' MeV/cm3'} - - - - - {toFixed(SM_ambienttemp) + ' K'} - - - - - {toFixed(SM_ambientpressure) + ' kPa'} - - - -
-
- -
act(ref, 'PRG_clear')} /> - )}> - - - {gases.map(gas => ( - - - {toFixed(gas.amount, 2) + '%'} - - - ))} - - -
-
-
- ); -}; - -/** - * A hack to force certain things (like tables) to position correctly - * inside bugged things, like Flex in Internet Explorer. - */ -const ForcedBox = props => { - const { height, children } = props; - return ( - - - {children} - - - ); -}; - -const SupermatterList = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { supermatters = [] } = data; - return ( -
act(ref, 'PRG_refresh')} /> - )}> - - {supermatters.map(sm => ( - - - {sm.uid + '. ' + sm.area_name} - - - Integrity: - - - - - -
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/NtosWrapper.js b/tgui-next/packages/tgui/interfaces/NtosWrapper.js deleted file mode 100644 index 2aea1d5d578..00000000000 --- a/tgui-next/packages/tgui/interfaces/NtosWrapper.js +++ /dev/null @@ -1,110 +0,0 @@ -import { act } from '../byond'; -import { Box, Button } from '../components'; -import { refocusLayout } from '../refocus'; - -export const NtosWrapper = props => { - const { state, children } = props; - const { config, data } = state; - const { ref } = config; - const { - PC_batteryicon, - PC_showbatteryicon, - PC_batterypercent, - PC_ntneticon, - PC_apclinkicon, - PC_stationtime, - PC_programheaders = [], - PC_showexitprogram, - } = data; - return ( -
-
{ - refocusLayout(); - }}> - - - {PC_stationtime} - - - NtOS - - -
- {PC_programheaders.map(header => ( - - - - ))} - - {PC_ntneticon && ( - - )} - - {!!PC_showbatteryicon && PC_batteryicon && ( - - {PC_batteryicon && ( - - )} - {PC_batterypercent && ( - PC_batterypercent - )} - - )} - {PC_apclinkicon && ( - - - - )} - {!!PC_showexitprogram && ( -
-
-
- {children} -
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/OperatingComputer.js b/tgui-next/packages/tgui/interfaces/OperatingComputer.js deleted file mode 100644 index b8aa2b4ff5e..00000000000 --- a/tgui-next/packages/tgui/interfaces/OperatingComputer.js +++ /dev/null @@ -1,159 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Button, LabeledList, Section, Tabs, NoticeBox, ProgressBar, AnimatedNumber } from '../components'; - -export const OperatingComputer = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const damageTypes = [ - { - label: "Brute", - type: "bruteLoss", - }, - { - label: "Burn", - type: "fireLoss", - }, - { - label: "Toxin", - type: "toxLoss", - }, - { - label: "Respiratory", - type: "oxyLoss", - }, - ]; - const { - table, - surgeries = [], - procedures = [], - patient = {}, - } = data; - return ( - - - {!table && ( - - No Table Detected - - )} -
-
- {patient ? ( - - - {patient.stat} - - - {patient.blood_type} - - - = 0 ? "good" : "average"} - content={( - - )} - /> - - {damageTypes.map(type => ( - - - )} - /> - - ))} - - ) : ( - "No Patient Detected" - )} -
-
- {procedures.length ? ( - procedures.map(procedure => ( -
- - - {procedure.next_step} - {procedure.chems_needed && ( - - - Required Chemicals: - -
- {procedure.chems_needed} -
- )} -
- {!!data.alternative_step && ( - - {procedure.alternative_step} - {procedure.alt_chems_needed && ( - - - Required Chemicals: - -
- {procedure.alt_chems_needed} -
- )} -
- )} -
-
- )) - ) : ( - "No Active Procedures" - )} -
-
-
- -
-
-
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/OreRedemptionMachine.js b/tgui-next/packages/tgui/interfaces/OreRedemptionMachine.js deleted file mode 100644 index 1ed93a0833d..00000000000 --- a/tgui-next/packages/tgui/interfaces/OreRedemptionMachine.js +++ /dev/null @@ -1,146 +0,0 @@ -import { toTitleCase } from 'common/string'; -import { Component, Fragment } from 'inferno'; -import { act } from '../byond'; -import { BlockQuote, Box, Button, NumberInput, Section, Table } from '../components'; - -export const OreRedemptionMachine = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - unclaimedPoints, - materials, - alloys, - diskDesigns, - hasDisk, - } = data; - return ( - -
-
- This machine only accepts ore.
- Gibtonite and Slag are not accepted. -
- - - Unclaimed points: - - {unclaimedPoints} -
-
- {hasDisk && ( - - -
-
- - {materials.map(material => ( - act(ref, 'Release', { - id: material.id, - sheets: amount, - })} /> - ))} -
-
-
- - {alloys.map(material => ( - act(ref, 'Smelt', { - id: material.id, - sheets: amount, - })} /> - ))} -
-
-
- ); -}; - -class MaterialRow extends Component { - constructor() { - super(); - this.state = { - amount: 1, - }; - } - - render() { - const { amount } = this.state; - const { material, onRelease } = this.props; - const amountAvailable = Math.floor(material.amount); - return ( - - - {toTitleCase(material.name).replace('Alloy', '')} - - - - {material.value && material.value + ' cr'} - - - - - {amountAvailable} sheets - - - - this.setState({ - amount: value, - })} /> - - - - {data.sheets} - {(data.sheets >= 1) && ( - - )} - - - - - - {data.current_heat < 100 ? ( - Nominal - ) : ( - data.current_heat < 200 ? ( - Caution - ) : ( - DANGER - ) - )} - - - -
- - - {data.power_output} - - - - - - - - {data.connected ? data.power_available : "Unconnected"} - - - -
-
); }; diff --git a/tgui-next/packages/tgui/interfaces/PowerMonitor.js b/tgui-next/packages/tgui/interfaces/PowerMonitor.js deleted file mode 100644 index 07cfead616a..00000000000 --- a/tgui-next/packages/tgui/interfaces/PowerMonitor.js +++ /dev/null @@ -1,223 +0,0 @@ -import { map, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; -import { toFixed } from 'common/math'; -import { pureComponentHooks } from 'common/react'; -import { Component, Fragment } from 'inferno'; -import { Box, Button, Chart, ColorBox, Flex, Icon, LabeledList, ProgressBar, Section, Table } from '../components'; - -const PEAK_DRAW = 500000; - -const powerRank = str => { - const unit = String(str.split(' ')[1]).toLowerCase(); - return ['w', 'kw', 'mw', 'gw'].indexOf(unit); -}; - -export class PowerMonitor extends Component { - constructor() { - super(); - this.state = { - sortByField: null, - }; - } - - render() { - const { state } = this.props; - const { config, data } = state; - const { ref } = config; - const { history } = data; - const { sortByField } = this.state; - const supply = history.supply[history.supply.length - 1] || 0; - const demand = history.demand[history.demand.length - 1] || 0; - const supplyData = history.supply.map((value, i) => [i, value]); - const demandData = history.demand.map((value, i) => [i, value]); - const maxValue = Math.max( - PEAK_DRAW, - ...history.supply, - ...history.demand); - // Process area data - const areas = flow([ - map((area, i) => ({ - ...area, - // Generate a unique id - id: area.name + i, - })), - sortByField === 'name' && sortBy(area => area.name), - sortByField === 'charge' && sortBy(area => -area.charge), - sortByField === 'draw' && sortBy( - area => -powerRank(area.load), - area => -parseFloat(area.load)), - ])(data.areas); - return ( - - - -
- - - - - - - - -
-
- -
- - -
-
-
-
- - - Sort by: - - this.setState({ - sortByField: sortByField !== 'name' && 'name', - })} /> - this.setState({ - sortByField: sortByField !== 'charge' && 'charge', - })} /> - this.setState({ - sortByField: sortByField !== 'draw' && 'draw', - })} /> - - - - - Area - - - Charge - - - Draw - - - Eqp - - - Lgt - - - Env - - - {areas.map((area, i) => ( - - - - - - - - - ))} -
- {area.name} - - - - {area.load} - - - - - - -
-
-
- ); - } -} - -const AreaCharge = props => { - const { charging, charge } = props; - return ( - - 50 - ? 'battery-half' - : 'battery-quarter' - ) - || charging === 1 && 'bolt' - || charging === 2 && 'battery-full' - )} - color={( - charging === 0 && ( - charge > 50 - ? 'yellow' - : 'red' - ) - || charging === 1 && 'yellow' - || charging === 2 && 'green' - )} /> - - {toFixed(charge) + '%'} - - - ); -}; - -AreaCharge.defaultHooks = pureComponentHooks; - -const AreaStatusColorBox = props => { - const { status } = props; - const power = Boolean(status & 2); - const mode = Boolean(status & 1); - const tooltipText = (power ? 'On' : 'Off') - + ` [${mode ? 'auto' : 'manual'}]`; - return ( - - ); -}; - -AreaStatusColorBox.defaultHooks = pureComponentHooks; diff --git a/tgui-next/packages/tgui/interfaces/Radio.js b/tgui-next/packages/tgui/interfaces/Radio.js deleted file mode 100644 index 0a68eef0608..00000000000 --- a/tgui-next/packages/tgui/interfaces/Radio.js +++ /dev/null @@ -1,110 +0,0 @@ -import { map } from 'common/collections'; -import { toFixed } from 'common/math'; -import { act } from '../byond'; -import { Box, Button, LabeledList, NumberInput, Section } from '../components'; -import { RADIO_CHANNELS } from '../constants'; - -export const Radio = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - freqlock, - frequency, - minFrequency, - maxFrequency, - listening, - broadcasting, - command, - useCommand, - subspace, - subspaceSwitchable, - } = data; - const tunedChannel = RADIO_CHANNELS - .find(channel => channel.freq === frequency); - const channels = map((value, key) => ({ - name: key, - status: !!value, - }))(data.channels); - return ( -
- - - {freqlock && ( - - {toFixed(frequency / 10, 1) + ' kHz'} - - ) || ( - toFixed(value, 1)} - onDrag={(e, value) => act(ref, 'frequency', { - adjust: (value - frequency / 10), - })} /> - )} - {tunedChannel && ( - - [{tunedChannel.name}] - - )} - - -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/RapidPipeDispenser.js b/tgui-next/packages/tgui/interfaces/RapidPipeDispenser.js deleted file mode 100644 index fc83985f2ce..00000000000 --- a/tgui-next/packages/tgui/interfaces/RapidPipeDispenser.js +++ /dev/null @@ -1,190 +0,0 @@ -import { classes } from 'common/react'; -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Box, Button, ColorBox, Flex, LabeledList, Section, Tabs } from '../components'; - -const ROOT_CATEGORIES = [ - 'Atmospherics', - 'Disposals', - 'Transit Tubes', -]; - -const ICON_BY_CATEGORY_NAME = { - 'Atmospherics': 'wrench', - 'Disposals': 'trash-alt', - 'Transit Tubes': 'bus', - 'Pipes': 'grip-lines', - 'Disposal Pipes': 'grip-lines', - 'Devices': 'microchip', - 'Heat Exchange': 'thermometer-half', - 'Station Equipment': 'microchip', -}; - -const PAINT_COLORS = { - grey: '#bbbbbb', - amethyst: '#a365ff', - blue: '#4466ff', - brown: '#b26438', - cyan: '#48eae8', - dark: '#808080', - green: '#1edd00', - orange: '#ffa030', - purple: '#b535ea', - red: '#ff3333', - violet: '#6e00f6', - yellow: '#ffce26', -}; - -const TOOLS = [ - { - name: 'Dispense', - bitmask: 1, - }, - { - name: 'Connect', - bitmask: 2, - }, - { - name: 'Destroy', - bitmask: 4, - }, - { - name: 'Paint', - bitmask: 8, - }, -]; - -export const RapidPipeDispenser = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - category: rootCategoryIndex, - categories = [], - selected_color, - piping_layer, - mode, - } = data; - const previews = data.preview_rows.flatMap(row => row.previews); - return ( - -
- - - {ROOT_CATEGORIES.map((categoryName, i) => ( -
- - -
- {rootCategoryIndex === 0 && ( - - {[1, 2, 3].map(layer => ( - act(ref, 'piping_layer', { - piping_layer: layer, - })} /> - ))} - - )} - - {previews.map(preview => ( - - ))} - -
-
- -
- - {categories.map(category => ( - - {() => category.recipes.map(recipe => ( - act(ref, 'pipe_type', { - pipe_type: recipe.pipe_index, - category: category.cat_name, - })} /> - ))} - - ))} - -
-
-
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SMES.js b/tgui-next/packages/tgui/interfaces/SMES.js deleted file mode 100644 index 98e0e86e22b..00000000000 --- a/tgui-next/packages/tgui/interfaces/SMES.js +++ /dev/null @@ -1,130 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { AnimatedNumber, Box, Button, LabeledList, ProgressBar, Section} from '../components'; - -export const SMES = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - - let inputState; - if (data.capacityPercent >= 100) { - inputState = "good"; - } - else if (data.inputting) { - inputState = "average"; - } - else { - inputState = "bad"; - } - let outputState; - if (data.outputting) { - outputState = "good"; - } - else if (data.charge > 0) { - outputState = "average"; - } - else { - outputState = "bad"; - } - - return ( - -
- -
-
- - act(ref, 'tryinput')}> - {data.inputAttempt ? "Auto" : "Off"} - - }> - - {data.capacityPercent >= 100 ? "Fully Charged" : data.inputting ? "Charging" : "Not Charging"} - - - - - - -
-
- - act(ref, 'tryoutput')}> - {data.outputAttempt ? "On" : "Off"} - - }> - - {data.outputting ? "Sending" : data.charge > 0 ? "Not Sending" : "No Charge"} - - - - - - -
-
); }; diff --git a/tgui-next/packages/tgui/interfaces/ShuttleManipulator.js b/tgui-next/packages/tgui/interfaces/ShuttleManipulator.js deleted file mode 100644 index 4023b305e7f..00000000000 --- a/tgui-next/packages/tgui/interfaces/ShuttleManipulator.js +++ /dev/null @@ -1,188 +0,0 @@ -import { map } from 'common/collections'; -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Button, LabeledList, Section, Tabs } from '../components'; - -export const ShuttleManipulator = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const shuttles = data.shuttles || []; - const templateObject = data.templates || {}; - const selected = data.selected || {}; - const existingShuttle = data.existing_shuttle || {}; - return ( - - - {() => ( -
- - {shuttles.map(shuttle => ( - - - - - - - - - ))} -
- - - {shuttle.name} - - {shuttle.id} - - {shuttle.status} - - {shuttle.mode} - {!!shuttle.timer && ( - - ({shuttle.timeleft}) -
-
- )} -
- - {() => ( -
- - {map((template, templateId) => { - const templates = template.templates || []; - return ( - - {templates.map(actualTemplate => { - const isSelected = (actualTemplate.shuttle_id === selected.shuttle_id); - return ( // Whoever made the structure being sent is an asshole -
act(ref, 'select_template', {shuttle_id: actualTemplate.shuttle_id})} /> - )}> - {(!!actualTemplate.description || !!actualTemplate.admin_notes) && ( - - {!!actualTemplate.description && ( - - {actualTemplate.description} - - )} - {!!actualTemplate.admin_notes && ( - - {actualTemplate.admin_notes} - - )} - - )} -
- ); - })} -
- ); - })(templateObject)} -
-
- )} -
- -
- {selected ? ( - -
- {(!!selected.description || !!selected.admin_notes) && ( - - {!!selected.description && ( - - {selected.description} - - )} - {!!selected.admin_notes && ( - - {selected.admin_notes} - - )} - - )} -
- {existingShuttle ? ( -
- - act(ref, 'jump_to', {type: "mobile", id: existingShuttle.id})} - /> - )}> - {existingShuttle.status} - {!!existingShuttle.timer && ( - - ({existingShuttle.timeleft}) - - )} - - -
- ) : ( -
- )} -
-
- - ) : "No shuttle selected"} -
- - - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SmartVend.js b/tgui-next/packages/tgui/interfaces/SmartVend.js deleted file mode 100644 index 5e6b9a4d3b9..00000000000 --- a/tgui-next/packages/tgui/interfaces/SmartVend.js +++ /dev/null @@ -1,63 +0,0 @@ -import { map } from 'common/collections'; -import { act } from '../byond'; -import { Button, NoticeBox, Section, Table } from '../components'; - -export const SmartVend = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( -
act(ref, 'Dry')}> - {data.drying ? "Stop drying" : "Dry"} - - )}> - {data.contents.length === 0 ? ( - - Unfortunately, this {data.name} is empty. - - ) : ( - - - - Item - - - - {data.verb ? data.verb : 'Dispense'} - - - {map((value, key) => ( - - - {value.name} - - - {value.amount} - - -
- )} -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SolarControl.js b/tgui-next/packages/tgui/interfaces/SolarControl.js deleted file mode 100644 index 04c382b2dbc..00000000000 --- a/tgui-next/packages/tgui/interfaces/SolarControl.js +++ /dev/null @@ -1,119 +0,0 @@ -import { toFixed } from 'common/math'; -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Box, Button, Grid, LabeledList, NumberInput, ProgressBar, Section } from '../components'; - -export const SolarControl = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - generated, - angle, - tracking_state, - tracking_rate, - connected_panels, - connected_tracker, - } = data; - return ( - -
act(ref, 'refresh')} /> - )}> - - - - - {connected_tracker ? 'OK' : 'N/A'} - - 0 ? 'good' : 'bad'}> - {connected_panels} - - - - - - - - - - - -
-
- - -
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/StationAlertConsole.js b/tgui-next/packages/tgui/interfaces/StationAlertConsole.js deleted file mode 100644 index 541f3d3364c..00000000000 --- a/tgui-next/packages/tgui/interfaces/StationAlertConsole.js +++ /dev/null @@ -1,59 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Section, Button } from '../components'; - -export const StationAlertConsole = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const categories = data.alarms || []; - const fire = categories['Fire'] || []; - const atmos = categories['Atmosphere'] || []; - const power = categories['Power'] || []; - return ( - -
-
    - {fire.length === 0 && ( -
  • - Systems Nominal -
  • - )} - {fire.map(alert => ( -
  • - {alert} -
  • - ))} -
-
-
-
    - {atmos.length === 0 && ( -
  • - Systems Nominal -
  • - )} - {atmos.map(alert => ( -
  • - {alert} -
  • - ))} -
-
-
-
    - {power.length === 0 && ( -
  • - Systems Nominal -
  • - )} - {power.map(alert => ( -
  • - {alert} -
  • - ))} -
-
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SuitStorageUnit.js b/tgui-next/packages/tgui/interfaces/SuitStorageUnit.js deleted file mode 100644 index f74d9fa781e..00000000000 --- a/tgui-next/packages/tgui/interfaces/SuitStorageUnit.js +++ /dev/null @@ -1,117 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Box, Button, LabeledList, Section, NoticeBox, Icon } from '../components'; - -export const SuitStorageUnit = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - locked, - open, - safeties, - uv_active, - occupied, - suit, - helmet, - mask, - storage, - } = data; - return ( - - {(!!occupied && !!safeties) && ( - - Biological entity detected in suit chamber. Please remove before continuing with operation. - - )} - {uv_active ? ( - - Contents are currently being decontaminated. Please wait. - - ) : ( -
- {!open && ( -
- )} -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/TankDispenser.js b/tgui-next/packages/tgui/interfaces/TankDispenser.js deleted file mode 100644 index b8e780ff240..00000000000 --- a/tgui-next/packages/tgui/interfaces/TankDispenser.js +++ /dev/null @@ -1,40 +0,0 @@ -import { act } from '../byond'; -import { Button, LabeledList, Section } from '../components'; - -export const TankDispenser = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( -
- - act(ref, "plasma")} - /> - )} - > - {data.plasma} - - act(ref, "oxygen")} - /> - )} - > - {data.oxygen} - - -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ThermoMachine.js b/tgui-next/packages/tgui/interfaces/ThermoMachine.js deleted file mode 100644 index 2aacd78b8c2..00000000000 --- a/tgui-next/packages/tgui/interfaces/ThermoMachine.js +++ /dev/null @@ -1,79 +0,0 @@ -import { toFixed } from 'common/math'; -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { AnimatedNumber, Button, LabeledList, NumberInput, Section } from '../components'; - -export const ThermoMachine = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( - -
- - - toFixed(value, 2)} /> - {' K'} - - - toFixed(value, 2)} /> - {' kPa'} - - -
-
act(ref, 'power')} /> - )}> - - - act(ref, "target", { - target: value, - })} /> - - -
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/TurbineComputer.js b/tgui-next/packages/tgui/interfaces/TurbineComputer.js deleted file mode 100644 index 16b2a9adce5..00000000000 --- a/tgui-next/packages/tgui/interfaces/TurbineComputer.js +++ /dev/null @@ -1,55 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Section, Button, LabeledList } from '../components'; -import { LabeledListItem } from '../components/LabeledList'; - -export const TurbineComputer = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( -
-
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/VaultController.js b/tgui-next/packages/tgui/interfaces/VaultController.js deleted file mode 100644 index 5e64ba4b2bc..00000000000 --- a/tgui-next/packages/tgui/interfaces/VaultController.js +++ /dev/null @@ -1,29 +0,0 @@ -import { toFixed } from 'common/math'; -import { act } from '../byond'; -import { Button, LabeledList, ProgressBar, Section } from '../components'; - -export const VaultController = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( -
act(ref, 'togglelock')} - /> - )}> - - - - - -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Wires.js b/tgui-next/packages/tgui/interfaces/Wires.js deleted file mode 100644 index 5956dad7ea3..00000000000 --- a/tgui-next/packages/tgui/interfaces/Wires.js +++ /dev/null @@ -1,64 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Button, LabeledList, Section, Box } from '../components'; -import { createLogger } from '../logging'; - -const logger = createLogger('AirAlarm'); - -export const Wires = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const wires = data.wires || []; - const statuses = data.status || []; - return ( - -
- - {wires.map(wire => ( - -
- {!!statuses.length && ( -
- {statuses.map(status => ( - - {status} - - ))} -
- )} -
- ); -}; diff --git a/tgui-next/packages/tgui/interfaces/common/BeakerContents.js b/tgui-next/packages/tgui/interfaces/common/BeakerContents.js deleted file mode 100644 index 235ab0e989f..00000000000 --- a/tgui-next/packages/tgui/interfaces/common/BeakerContents.js +++ /dev/null @@ -1,19 +0,0 @@ -import { Box } from '../../components'; - -export const BeakerContents = props => { - const { beakerLoaded, beakerContents } = props; - return ( - - {!beakerLoaded && ( - - ) || beakerContents.length === 0 && ( - - )} - {beakerContents.map(chemical => ( - - {chemical.volume} units of {chemical.name} - - ))} - - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/common/InterfaceLockNoticeBox.js b/tgui-next/packages/tgui/interfaces/common/InterfaceLockNoticeBox.js deleted file mode 100644 index 36e889dee56..00000000000 --- a/tgui-next/packages/tgui/interfaces/common/InterfaceLockNoticeBox.js +++ /dev/null @@ -1,37 +0,0 @@ -import { Button, Flex, NoticeBox } from '../../components'; -import { Fragment } from 'inferno'; - -export const InterfaceLockNoticeBox = props => { - const { siliconUser, locked, onLockStatusChange, accessText } = props; - // For silicon users - if (siliconUser) { - return ( - - - - Interface lock status: - - - -
+ + + ); +}; +``` + +Here are the key variables you get from a `useBackend(context)` function: + +- `config` is part of core tgui. It contains meta-information about the + interface and who uses it, BYOND refs to various objects, and so forth. + You are rarely going to use it, but sometimes it can be used to your + advantage when doing complex UIs. +- `data` is the data returned from `ui_data` and `ui_static_data` procs in + your DM code. Pretty straight forward. + - Note, that javascript doesn't have associative arrays, so when you + return an associative list from DM, it will be available in `data` as a + javascript object instead of an array. You can use it normally + like so: `object.key`, so it's not a problem if it's representing a + data structure, but common `Array` methods, such as `array.map(item => ...)`, + are not available on it. Always prefer returning clean arrays from your + code, since arrays are easier to work with in javascript! +- `act(name, params)` is a function, which you can call to dispatch an action + to your DM code. It will be processed in `ui_act` proc. Action name will be + available in `params["action"]`, mixed together with the rest of parameters + you have passed in `params` object. + +**Let's talk about the syntax.** + +The syntax you're seeing here is called JSX - a very simple extension of the +core javascript language. It's basically a pre-processor, that takes +expressions that look like html, and turns them into function calls. + +Take a look at this example: + +```jsx +
You are in {status} condition!
+``` + +After compiling the code above, this is what it becomes: + +```js +createElement( + 'div', + { className: 'color-' + status }, + 'You are in ', + status, + ' condition!', +); +``` + +It is very important to remember, that JSX is just a javascript expression +made out of `createElement` function calls. Naturally, this allows doing +all sorts of stuff on these expressions, just like you would with anything +else in javascript. + +Take a look at these examples: + +**Render an element inside of another element if `showProgress` is true.** + +This example uses the `&&` operator (the logical AND). It returns +the first operand if it evaluates to `false`, and returns the second operand +if it evaluates to `true`. + +If `showProgress` is `true`, the whole expression evaluates +to a `` element. If `showProgress` is `false`, the whole +expression evaluates to `false`, and `false` is not rendered by React. + +```jsx +{showProgress && } +``` + +You can also use the `||` operator (the logical OR), which works the same way, +except it will return the second operand on `false` instead of `true`. + +**Loop over the array to map every item to a corresponding React element.** + +`Array.map()` is a method, that calls a function on every item in the array, +and builds a new array based on what was returned by that function. + +```jsx + + {items.map((item) => ( + + {item.content} + + ))} + +``` + +If you need more examples of what you can do with React, see the +[interface conversion guide](docs/converting-old-tgui-interfaces.md). + +#### Splitting UIs into smaller, modular components + +You interface will eventually get really, really big. The easiest thing +you can do in this situation, is divide and conquer. Grab a chunk of your +JSX code, and wrap it into a second, smaller React component: + +```jsx +import { useBackend } from '../backend'; +import { Button, LabeledList, Section } from '../components'; +import { Window } from '../layouts'; + +export const SampleInterface = (props, context) => { + return ( + + + + + + ); +}; + +const HealthStatus = (props, context) => { + const { act, data } = useBackend(context); + const { user } = props; + const { health, color } = data; + return ( +
+ + {health} + {color} + +
+ ); +}; +``` + +## Copypasta + +We all do it, even the best of us. If you just want to make a tgui **fast**, +here's what you need (note that you'll probably be forced to clean your shit up +upon code review): + +```dm +/obj/copypasta/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "copypasta") + ui.open() + +/obj/copypasta/ui_data(mob/user) + var/list/data = list() + data["var"] = var + return data + +/obj/copypasta/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return + switch(action) + if("copypasta") + var/newvar = params["var"] + // A demo of proper input sanitation. + var = CLAMP(newvar, min_val, max_val) + . = TRUE + update_icon() // Not applicable to all objects. +``` + +And the template: + +```jsx +import { useBackend } from '../backend'; +import { Button, LabeledList, Section } from '../components'; +import { Window } from '../layouts'; + +export const SampleInterface = (props, context) => { + const { act, data } = useBackend(context); + // Extract `health` and `color` variables from the `data` object. + const { health, color } = data; + return ( + + +
+ + {health} + {color} + +
+
+
+ ); +}; +``` diff --git a/tgui/docs/writing-tests.md b/tgui/docs/writing-tests.md new file mode 100644 index 00000000000..daa29115d9e --- /dev/null +++ b/tgui/docs/writing-tests.md @@ -0,0 +1,19 @@ +## Jest + +You can now write and run unit tests in tgui. + +It's quite simple: create a file ending in `.test.ts` or `.spec.ts` (usually with the same filename as the file you're testing), and create a test case: + +```js +test('something', () => { + expect('a').toBe('a'); +}); +``` + +Refer to [README](../README.md) to learn how to run tests. + +There is an example test in `packages/common/react.spec.ts`. + +You can read more about Jest here: https://jestjs.io/docs/en/getting-started + +Note, that there is still no real solution to test UIs for now, even though a lot of the support is here (jest + jsdom). That will come later. diff --git a/tgui/global.d.ts b/tgui/global.d.ts new file mode 100644 index 00000000000..ef127804749 --- /dev/null +++ b/tgui/global.d.ts @@ -0,0 +1,208 @@ +/** + * @file + * @copyright 2021 Aleksej Komarov + * @license MIT + */ + +// Webpack asset modules. +// Should match extensions used in webpack config. +declare module '*.png' { + const content: string; + export default content; +} + +declare module '*.jpg' { + const content: string; + export default content; +} + +declare module '*.svg' { + const content: string; + export default content; +} + +namespace JSX { + interface IntrinsicElements { + marquee: any; + blink: any; + } +} + +type TguiMessage = { + type: string; + payload?: any; + [key: string]: any; +}; + +type ByondType = { + /** + * ID of the Byond window this script is running on. + * Can be used as a parameter to winget/winset. + */ + windowId: string; + + /** + * True if javascript is running in BYOND. + */ + IS_BYOND: boolean; + + /** + * Version of Blink engine of WebView2. Null if N/A. + */ + BLINK: number | null; + + /** + * If `true`, unhandled errors and common mistakes result in a blue screen + * of death, which stops this window from handling incoming messages and + * closes the active instance of tgui datum if there was one. + * + * It can be defined in window.initialize() in DM, or changed in runtime + * here via this property to `true` or `false`. + * + * It is recommended that you keep this ON to detect hard to find bugs. + */ + strictMode: boolean; + + /** + * The external URL for the IndexedDB IFrame to use as the origin + */ + storageCdn: string; + + /** + * Makes a BYOND call. + * + * If path is empty, this will trigger a Topic call. + * You can reference a specific object by setting the "src" parameter. + * + * See: https://secure.byond.com/docs/ref/skinparams.html + */ + call(path: string, params: object): void; + + /** + * Makes an asynchronous BYOND call. Returns a promise. + */ + callAsync(path: string, params: object): Promise; + + /** + * Makes a Topic call. + * + * You can reference a specific object by setting the "src" parameter. + */ + topic(params: object): void; + + /** + * Runs a command or a verb. + */ + command(command: string): void; + + /** + * Retrieves all properties of the BYOND skin element. + * + * Returns a promise with a key-value object containing all properties. + */ + winget(id: string | null): Promise>; + + /** + * Retrieves all properties of the BYOND skin element. + * + * Returns a promise with a key-value object containing all properties. + */ + winget(id: string | null, propName: '*'): Promise>; + + /** + * Retrieves an exactly one property of the BYOND skin element, + * as defined in `propName`. + * + * Returns a promise with the value of that property. + */ + winget(id: string | null, propName: string): Promise; + + /** + * Retrieves multiple properties of the BYOND skin element, + * as defined in the `propNames` array. + * + * Returns a promise with a key-value object containing listed properties. + */ + winget(id: string | null, propNames: string[]): Promise>; + + /** + * Assigns properties to BYOND skin elements in bulk. + */ + winset(props: object): void; + + /** + * Assigns properties to the BYOND skin element. + */ + winset(id: string | null, props: object): void; + + /** + * Sets a property on the BYOND skin element to a certain value. + */ + winset(id: string | null, propName: string, propValue: any): void; + + /** + * Parses BYOND JSON. + * + * Uses a special encoding to preserve `Infinity` and `NaN`. + */ + parseJson(text: string): any; + + /** + * Sends a message to `/datum/tgui_window` which hosts this window instance. + */ + sendMessage(type: string, payload?: any): void; + sendMessage(message: TguiMessage): void; + + /** + * Subscribe to incoming messages that were sent from `/datum/tgui_window`. + */ + subscribe(listener: (type: string, payload: any) => void): void; + + /** + * Subscribe to incoming messages *of some specific type* + * that were sent from `/datum/tgui_window`. + */ + subscribeTo(type: string, listener: (payload: any) => void): void; + + /** + * Loads a stylesheet into the document. + */ + loadCss(url: string): void; + + /** + * Loads a script into the document. + */ + loadJs(url: string): void; + + /** + * Maps icons to their ref + */ + iconRefMap: Record; + + /** + * Downloads a blob, platform-agnostic + */ + saveBlob(blob: Blob, filename: string, ext: string): void; +}; + +/** + * Object that provides access to Byond Skin API and is available in + * any tgui application. + */ +const Byond: ByondType = {}; + +interface Window { + Byond: ByondType; + __augmentStack__: (stack: string, error?: Error) => string; + + // IE IndexedDB stuff. + msIndexedDB: IDBFactory; + msIDBTransaction: IDBTransaction; + + // 516 byondstorage API. + hubStorage: Storage; + domainStorage: Storage; + serverStorage: Storage; + + __chatRenderer__: any; +} diff --git a/tgui/gulp/css.js b/tgui/gulp/css.js deleted file mode 100644 index 504ccf4038d..00000000000 --- a/tgui/gulp/css.js +++ /dev/null @@ -1,31 +0,0 @@ -import * as f from './flags' -import { gulp as g, postcss as s } from './plugins' - -const entry = 'tgui.styl' - -import gulp from 'gulp' -export function css () { - return gulp.src(`${f.src}/${entry}`) - .pipe(g.if(f.debug, g.sourcemaps.init({loadMaps: true}))) - .pipe(g.stylus({ - url: 'data-url', - paths: [ f.src ] - })) - .pipe(g.postcss([ - s.autoprefixer({ browsers: ['last 2 versions', 'ie >= 8'] }), - s.gradient, - s.opacity, - s.rgba({oldie: true}), - s.plsfilters({oldIE: true}), - s.fontweights, - ... f.min ? [s.cssnano()] : [], - ])) - .pipe(g.bytediff.start()) - .pipe(g.if(f.debug, g.sourcemaps.write())) - .pipe(g.bytediff.stop()) - .pipe(gulp.dest(f.dest)) -} -export function watch_css () { - gulp.watch(`${f.src}/**/*.styl`, css) - return css() -} diff --git a/tgui/gulp/flags.js b/tgui/gulp/flags.js deleted file mode 100644 index cc615f63d4a..00000000000 --- a/tgui/gulp/flags.js +++ /dev/null @@ -1,7 +0,0 @@ -const flags = require('minimist')(process.argv.slice(2)) - -export const src = flags.src || 'src' -export const dest = flags.dest || 'assets' - -export const debug = flags.debug || flags.d -export const min = flags.min || flags.m diff --git a/tgui/gulp/js.js b/tgui/gulp/js.js deleted file mode 100644 index fb88a80e79d..00000000000 --- a/tgui/gulp/js.js +++ /dev/null @@ -1,68 +0,0 @@ -import * as f from './flags' -import { browserify as b, gulp as g } from './plugins' - -const entry = 'tgui.js' - -import { transform as babel } from 'babel-core' -import { readFileSync as read } from 'fs' -b.componentify.compilers['text/javascript'] = function (source, file) { - const config = { sourceMaps: true } - Object.assign(config, JSON.parse(read(`${f.src}/.babelrc`, 'utf8'))) - const compiled = babel(source, config) - - return { source: compiled.code, map: compiled.map } -} -import { render as stylus } from 'stylus' -b.componentify.compilers['text/stylus'] = function (source, file) { - const config = { filename: file } - const compiled = stylus(source, config) - - return { source: compiled } -} - -import browserify from 'browserify' -const bundle = browserify(`${f.src}/${entry}`, { - debug: f.debug, - cache: {}, - packageCache: {}, - extensions: [ '.js', '.ract' ], - paths: [ f.src ] -}) -if (f.min) bundle.plugin(b.collapse) -bundle - .transform(b.babelify) - .plugin(b.helpers) - .transform(b.componentify) - .transform(b.globify) - .transform(b.es3ify, { global: true }) - -import buffer from 'vinyl-buffer' -import gulp from 'gulp' -import source from 'vinyl-source-stream' -export function js () { - return bundle.bundle() - .pipe(source(entry)) - .pipe(buffer()) - .pipe(g.if(f.debug, g.sourcemaps.init({loadMaps: true}))) - .pipe(g.bytediff.start()) - .pipe(g.if(f.min, g.uglify({ - mangle: true, - compress: { - unsafe: false, - }, - ie8: true, - }))) - .pipe(g.if(f.debug, g.sourcemaps.write())) - .pipe(g.bytediff.stop()) - .pipe(gulp.dest(f.dest)) -} -import gulplog from 'gulplog' -export function watch_js () { - bundle.plugin(b.watchify) - bundle.on('update', js) - bundle.on('error', err => { - gulplog.error(err.toString()) - this.emit('end') - }) - return js() -} diff --git a/tgui/gulp/plugins.js b/tgui/gulp/plugins.js deleted file mode 100644 index 3893e9e59da..00000000000 --- a/tgui/gulp/plugins.js +++ /dev/null @@ -1,21 +0,0 @@ -export const browserify = { - babelify: require('babelify'), - collapse: require('bundle-collapser/plugin'), - componentify: require('ractive-componentify'), - es3ify: require('es3ify'), - globify: require('require-globify'), - helpers: require('babelify-external-helpers'), - watchify: require('watchify') -} - -export const gulp = require('gulp-load-plugins')({ replaceString: /^gulp(-|\.)|-/g }) - -export const postcss = { - autoprefixer: require('autoprefixer'), - fontweights: require('postcss-font-weights'), - gradient: require('postcss-filter-gradient'), - opacity: require('postcss-opacity'), - plsfilters: require('pleeease-filters'), - rgba: require('postcss-color-rgba-fallback'), - cssnano: require('cssnano'), -} diff --git a/tgui/gulp/reload.js b/tgui/gulp/reload.js deleted file mode 100644 index f5b88bed9d9..00000000000 --- a/tgui/gulp/reload.js +++ /dev/null @@ -1,10 +0,0 @@ -const out = 'assets' - -import { exec } from 'child_process' -export function reload () { - return exec('reload.bat') -} -import gulp from 'gulp' -export function watch_reload () { - gulp.watch(`${out}/**`, reload) -} diff --git a/tgui/gulp/size.js b/tgui/gulp/size.js deleted file mode 100644 index 6e40e128997..00000000000 --- a/tgui/gulp/size.js +++ /dev/null @@ -1,9 +0,0 @@ -import { gulp as g } from './plugins' - -const out = 'assets' - -import gulp from 'gulp' -export function size () { - return gulp.src(`${out}/**`) - .pipe(g.size()) -} diff --git a/tgui/gulpfile.babel.js b/tgui/gulpfile.babel.js deleted file mode 100644 index de491a5eca8..00000000000 --- a/tgui/gulpfile.babel.js +++ /dev/null @@ -1,12 +0,0 @@ -import gulp from 'gulp' - -import { css, watch_css } from './gulp/css' -import { js, watch_js } from './gulp/js' -import { reload, watch_reload } from './gulp/reload' -import { size } from './gulp/size' - -gulp.task(reload) -gulp.task(size) - -gulp.task('default', gulp.series(gulp.parallel(css, js), size)) -gulp.task('watch', gulp.parallel(watch_css, watch_js, watch_reload)) diff --git a/tgui/happydom.ts b/tgui/happydom.ts new file mode 100644 index 00000000000..18a7051a49e --- /dev/null +++ b/tgui/happydom.ts @@ -0,0 +1,5 @@ +import { GlobalRegistrator } from '@happy-dom/global-registrator'; + +GlobalRegistrator.register(); + +import 'packages/tgui/__mocks__/setup.ts'; diff --git a/tgui/install_dependencies.bat b/tgui/install_dependencies.bat deleted file mode 100644 index 4d5b922fe0c..00000000000 --- a/tgui/install_dependencies.bat +++ /dev/null @@ -1,8 +0,0 @@ -@echo off -echo node.js 5.3.0 or newer must be installed for this script to work. -echo If this script fails, try closing editors and running it again first. -echo Any warnings about optional dependencies can be safely ignored. -pause -REM Install dependencies -npm ci -pause diff --git a/tgui/package-lock.json b/tgui/package-lock.json deleted file mode 100644 index 63c46b31beb..00000000000 --- a/tgui/package-lock.json +++ /dev/null @@ -1,10545 +0,0 @@ -{ - "name": "tgui", - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@types/q": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", - "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" - }, - "JSONStream": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", - "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=", - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "accord": { - "version": "0.26.4", - "resolved": "https://registry.npmjs.org/accord/-/accord-0.26.4.tgz", - "integrity": "sha1-/EyNPrq0BqB8sogZuFllHESpLoA=", - "requires": { - "convert-source-map": "^1.2.0", - "glob": "^7.0.5", - "indx": "^0.2.3", - "lodash.clone": "^4.3.2", - "lodash.defaults": "^4.0.1", - "lodash.flatten": "^4.2.0", - "lodash.merge": "^4.4.0", - "lodash.partialright": "^4.1.4", - "lodash.pick": "^4.2.1", - "lodash.uniq": "^4.3.0", - "resolve": "^1.1.7", - "semver": "^5.3.0", - "uglify-js": "^2.7.0", - "when": "^3.7.7" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==" - }, - "acorn-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.3.0.tgz", - "integrity": "sha512-efP54n3d1aLfjL2UMdaXa6DsswwzJeI5rqhbFvXMrKiJ6eJFpf+7R0zN7t8IC+XKn2YOAFAv6xbBNgHUkoHWLw==", - "requires": { - "acorn": "^5.4.1", - "xtend": "^4.0.1" - }, - "dependencies": { - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==" - } - } - }, - "acorn-walk": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", - "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==" - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" - }, - "ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "requires": { - "ansi-wrap": "^0.1.0" - } - }, - "ansi-cyan": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", - "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-red": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", - "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", - "requires": { - "buffer-equal": "^1.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", - "requires": { - "make-iterator": "^1.0.0" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", - "requires": { - "make-iterator": "^1.0.0" - } - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" - }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" - }, - "array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", - "requires": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" - } - } - }, - "array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" - } - } - }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=" - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" - }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" - }, - "array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", - "requires": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.3.0.tgz", - "integrity": "sha1-A5OaYiWCqBLMICMgoLmlbJuBWEk=", - "requires": { - "util": "0.10.3" - } - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "astw": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", - "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=", - "requires": { - "acorn": "^4.0.3" - } - }, - "async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" - } - }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" - }, - "async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", - "requires": { - "async-done": "^1.2.2" - } - }, - "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=" - }, - "autoprefixer": { - "version": "6.7.7", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", - "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", - "requires": { - "browserslist": "^1.7.6", - "caniuse-db": "^1.0.30000634", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^5.2.16", - "postcss-value-parser": "^3.2.3" - }, - "dependencies": { - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - } - } - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-external-helpers": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz", - "integrity": "sha1-IoX0iwK9Xe3oUXXK+MYuhq3M76E=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "requires": { - "regenerator-transform": "^0.10.0" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-polyfill": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", - "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", - "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" - } - } - }, - "babel-preset-es2015": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", - "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.24.1", - "babel-plugin-transform-es2015-classes": "^6.24.1", - "babel-plugin-transform-es2015-computed-properties": "^6.24.1", - "babel-plugin-transform-es2015-destructuring": "^6.22.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", - "babel-plugin-transform-es2015-for-of": "^6.22.0", - "babel-plugin-transform-es2015-function-name": "^6.24.1", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", - "babel-plugin-transform-es2015-modules-umd": "^6.24.1", - "babel-plugin-transform-es2015-object-super": "^6.24.1", - "babel-plugin-transform-es2015-parameters": "^6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", - "babel-plugin-transform-regenerator": "^6.24.1" - } - }, - "babel-preset-es2015-loose": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/babel-preset-es2015-loose/-/babel-preset-es2015-loose-7.0.0.tgz", - "integrity": "sha1-/YDIXTsgy/MJvQzjCjY4DFeEvwY=", - "requires": { - "modify-babel-preset": "^1.0.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babelify": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.2.0.tgz", - "integrity": "sha1-WEJJvFBmth+YSz50XthVIDyexz4=", - "requires": { - "babel-core": "^6.0.14", - "object-assign": "^4.0.0" - } - }, - "babelify-external-helpers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babelify-external-helpers/-/babelify-external-helpers-1.1.0.tgz", - "integrity": "sha1-79pgfxWINmIAGeQu09yMkVZMrM8=", - "requires": { - "insert-module-globals": "^7.0.1", - "through2": "^2.0.0", - "xtend": "^4.0.1" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", - "requires": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, - "base62": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/base62/-/base62-0.1.1.tgz", - "integrity": "sha1-e0F0wvlESXU7EcJlHAg9qEGnsIQ=" - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" - }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=" - }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=" - }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browser-pack": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", - "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", - "requires": { - "JSONStream": "^1.0.3", - "combine-source-map": "~0.8.0", - "defined": "^1.0.0", - "safe-buffer": "^5.1.1", - "through2": "^2.0.0", - "umd": "^3.0.0" - } - }, - "browser-resolve": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", - "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" - } - } - }, - "browser-unpack": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browser-unpack/-/browser-unpack-1.2.0.tgz", - "integrity": "sha1-NXruMfxGeDFoTQY+Q1XgcKeClw0=", - "requires": { - "acorn": "^4.0.3", - "browser-pack": "^5.0.1", - "concat-stream": "^1.5.0", - "minimist": "^1.1.1" - }, - "dependencies": { - "browser-pack": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-5.0.1.tgz", - "integrity": "sha1-QZdxmyDG4KqglFHFER5T77b7wY0=", - "requires": { - "JSONStream": "^1.0.3", - "combine-source-map": "~0.6.1", - "defined": "^1.0.0", - "through2": "^1.0.0", - "umd": "^3.0.0" - } - }, - "combine-source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.6.1.tgz", - "integrity": "sha1-m0oJwxYDPXaODxHgKfonMOB5rZY=", - "requires": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.5.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.4.2" - } - }, - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" - }, - "inline-source-map": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.5.0.tgz", - "integrity": "sha1-Skxd2OT7Xps82mDIIt+tyu5m4K8=", - "requires": { - "source-map": "~0.4.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "requires": { - "amdefine": ">=0.0.4" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, - "browserify": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-13.0.0.tgz", - "integrity": "sha1-jyI7sk/07kM15r6pZx3ilOQ7pqM=", - "requires": { - "JSONStream": "^1.0.3", - "assert": "~1.3.0", - "browser-pack": "^6.0.1", - "browser-resolve": "^1.11.0", - "browserify-zlib": "~0.1.2", - "buffer": "^4.1.0", - "concat-stream": "~1.5.1", - "console-browserify": "^1.1.0", - "constants-browserify": "~1.0.0", - "crypto-browserify": "^3.0.0", - "defined": "^1.0.0", - "deps-sort": "^2.0.0", - "domain-browser": "~1.1.0", - "duplexer2": "~0.1.2", - "events": "~1.1.0", - "glob": "^5.0.15", - "has": "^1.0.0", - "htmlescape": "^1.1.0", - "https-browserify": "~0.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^7.0.0", - "isarray": "0.0.1", - "labeled-stream-splicer": "^2.0.0", - "module-deps": "^4.0.2", - "os-browserify": "~0.1.1", - "parents": "^1.0.1", - "path-browserify": "~0.0.0", - "process": "~0.11.0", - "punycode": "^1.3.2", - "querystring-es3": "~0.2.0", - "read-only-stream": "^2.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.4", - "shasum": "^1.0.0", - "shell-quote": "^1.4.3", - "stream-browserify": "^2.0.0", - "stream-http": "^2.0.0", - "string_decoder": "~0.10.0", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^2.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "~0.0.0", - "url": "~0.11.0", - "util": "~0.10.1", - "vm-browserify": "~0.0.1", - "xtend": "^4.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - } - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz", - "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "browserify-transform-tools": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/browserify-transform-tools/-/browserify-transform-tools-1.7.0.tgz", - "integrity": "sha1-g+J3Ih9jJZvtLn6yooOpcKUB9MQ=", - "requires": { - "falafel": "^2.0.0", - "through": "^2.3.7" - } - }, - "browserify-zlib": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", - "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", - "requires": { - "pako": "~0.2.0" - } - }, - "browserslist": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", - "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", - "requires": { - "caniuse-db": "^1.0.30000639", - "electron-to-chromium": "^1.2.7" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=" - }, - "buffer-from": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" - }, - "bundle-collapser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bundle-collapser/-/bundle-collapser-1.2.1.tgz", - "integrity": "sha1-4RmvySY45EC5CF9Hrggfp1bLoz0=", - "requires": { - "browser-pack": "^5.0.1", - "browser-unpack": "^1.1.0", - "concat-stream": "^1.5.0", - "falafel": "^1.2.0", - "minimist": "^1.1.1", - "through2": "^2.0.0" - }, - "dependencies": { - "acorn": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", - "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=" - }, - "browser-pack": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-5.0.1.tgz", - "integrity": "sha1-QZdxmyDG4KqglFHFER5T77b7wY0=", - "requires": { - "JSONStream": "^1.0.3", - "combine-source-map": "~0.6.1", - "defined": "^1.0.0", - "through2": "^1.0.0", - "umd": "^3.0.0" - }, - "dependencies": { - "through2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", - "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", - "requires": { - "readable-stream": ">=1.1.13-1 <1.2.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, - "combine-source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.6.1.tgz", - "integrity": "sha1-m0oJwxYDPXaODxHgKfonMOB5rZY=", - "requires": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.5.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.4.2" - } - }, - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" - }, - "falafel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-1.2.0.tgz", - "integrity": "sha1-wY0k71CRF0pJfzGM0ksCaiXN2rQ=", - "requires": { - "acorn": "^1.0.3", - "foreach": "^2.0.5", - "isarray": "0.0.1", - "object-keys": "^1.0.6" - } - }, - "inline-source-map": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.5.0.tgz", - "integrity": "sha1-Skxd2OT7Xps82mDIIt+tyu5m4K8=", - "requires": { - "source-map": "~0.4.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "requires": { - "amdefine": ">=0.0.4" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "cached-path-relative": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", - "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==" - }, - "requester-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/requester-callsite/-/requester-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "requires": { - "callsites": "^2.0.0" - } - }, - "requester-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/requester-path/-/requester-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "requires": { - "requester-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" - }, - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - } - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - }, - "dependencies": { - "browserslist": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.2.tgz", - "integrity": "sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==", - "requires": { - "caniuse-lite": "^1.0.30000974", - "electron-to-chromium": "^1.3.150", - "node-releases": "^1.1.23" - } - }, - "electron-to-chromium": { - "version": "1.3.163", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.163.tgz", - "integrity": "sha512-uCEoqQeKrjlhUSUudY0XvyNVDhWR5XmnCIV0WXr2Qo9PVzEVXI75LHGtzwro9Qh8NNetRjSitrm8AfQvPGaSqA==" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" - } - } - }, - "caniuse-db": { - "version": "1.0.30000843", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000843.tgz", - "integrity": "sha1-T36FAfVX3JvNN90zrIWQXHZe/sI=" - }, - "caniuse-lite": { - "version": "1.0.30000974", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000974.tgz", - "integrity": "sha512-xc3rkNS/Zc3CmpMKuczWEdY2sZgx09BkAxfvkxlAEBTqcMHeL8QnPqhKse+5sRTi3nrw2pJwToD2WvKn1Uhvww==" - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "dependencies": { - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - } - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" - }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=" - }, - "cloneable-readable": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", - "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", - "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", - "requires": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", - "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - }, - "dependencies": { - "color-string": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", - "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - } - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-string": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", - "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", - "requires": { - "color-name": "^1.0.0" - } - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" - }, - "combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", - "requires": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.6.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.5.3" - }, - "dependencies": { - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" - } - } - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "requires": { - "date-now": "^0.1.4" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" - }, - "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, - "copy-props": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", - "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", - "requires": { - "each-props": "^1.3.0", - "is-plain-object": "^2.0.1" - } - }, - "core-js": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", - "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "dependencies": { - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - } - } - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "css": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", - "requires": { - "inherits": "^2.0.3", - "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "css-font-weight-names": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/css-font-weight-names/-/css-font-weight-names-0.2.1.tgz", - "integrity": "sha1-VxDUha0pX2s/HO7EH4guMkpGtRY=" - }, - "css-parse": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", - "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=" - }, - "css-select": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz", - "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^2.1.2", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" - }, - "css-tree": { - "version": "1.0.0-alpha.28", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.28.tgz", - "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", - "requires": { - "mdn-data": "~1.1.0", - "source-map": "^0.5.3" - } - }, - "css-unit-converter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", - "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=" - }, - "css-url-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz", - "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=" - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" - }, - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "cssnano": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssnano-preset-default": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", - "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.2", - "postcss-unique-selectors": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=" - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=" - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==" - }, - "csso": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz", - "integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==", - "requires": { - "css-tree": "1.0.0-alpha.29" - }, - "dependencies": { - "css-tree": { - "version": "1.0.0-alpha.29", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", - "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", - "requires": { - "mdn-data": "~1.1.0", - "source-map": "^0.5.3" - } - } - } - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "requires": { - "array-find-index": "^1.0.1" - } - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" - }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", - "requires": { - "kind-of": "^5.0.2" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=" - }, - "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", - "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" - }, - "deps-sort": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", - "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", - "requires": { - "JSONStream": "^1.0.3", - "shasum": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^2.0.0" - } - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "^2.0.0" - } - }, - "detective": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", - "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", - "requires": { - "acorn": "^5.2.1", - "defined": "^1.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==" - } - } - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - } - }, - "dom4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dom4/-/dom4-1.7.0.tgz", - "integrity": "sha1-Vd54u9UkXQHHeQaYSPtAsmFu3vg=" - }, - "domain-browser": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", - "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=" - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "requires": { - "is-obj": "^1.0.0" - } - }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "requires": { - "readable-stream": "^2.0.2" - } - }, - "duplexify": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", - "requires": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" - } - }, - "electron-to-chromium": { - "version": "1.3.47", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.47.tgz", - "integrity": "sha1-dk6IfKkQTQGgrI6r7n38DizhQQQ=" - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" - }, - "dependencies": { - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - } - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es3ify": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/es3ify/-/es3ify-0.2.1.tgz", - "integrity": "sha1-gquWnmAkiH+SQMt0LPGeYsnrnwo=", - "requires": { - "esprima": "^2.7.1", - "jstransform": "~3.0.0", - "through": "~2.3.4" - }, - "dependencies": { - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" - } - } - }, - "es5-ext": { - "version": "0.10.50", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", - "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "^1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-promise": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz", - "integrity": "sha1-lu258v2wGZWCKyY92KratnSBgbw=" - }, - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, - "falafel": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.1.0.tgz", - "integrity": "sha1-lrsXdh2rqU9G0AFzizzt86Z/4Gw=", - "requires": { - "acorn": "^5.0.0", - "foreach": "^2.0.5", - "isarray": "0.0.1", - "object-keys": "^1.0.6" - }, - "dependencies": { - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - } - } - }, - "fancy-log": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", - "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "time-stamp": "^1.0.0" - } - }, - "fg-loadcss": { - "version": "1.0.0-0", - "resolved": "https://registry.npmjs.org/fg-loadcss/-/fg-loadcss-1.0.0-0.tgz", - "integrity": "sha1-ZDkPKyWzHClDQPtR7Q8UgLe48FI=" - }, - "filesize": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.1.6.tgz", - "integrity": "sha1-WISSTvyBpkTjcJqsQDIWGDw9eYo=" - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "filter-gradient": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/filter-gradient/-/filter-gradient-1.0.1.tgz", - "integrity": "sha1-ikFRiyIoQ1H6ymNqb9sba5BMogc=", - "requires": { - "color": "^0.10.1" - }, - "dependencies": { - "color": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/color/-/color-0.10.1.tgz", - "integrity": "sha1-wEGI34KiCd3rzOzazT7DIPGTc58=", - "requires": { - "color-convert": "^0.5.3", - "color-string": "^0.3.0" - } - }, - "color-convert": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", - "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" - } - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - } - }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "requires": { - "for-in": "^1.0.1" - } - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" - }, - "fork-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", - "requires": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "get-requester-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-requester-file/-/get-requester-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" - }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" - }, - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", - "requires": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "glob-watcher": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", - "requires": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "object.defaults": "^1.1.0" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "glogg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz", - "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", - "requires": { - "sparkles": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "gulp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", - "requires": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" - }, - "dependencies": { - "gulp-cli": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz", - "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==", - "requires": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.1.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.0.1", - "yargs": "^7.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "gulp-bytediff": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulp-bytediff/-/gulp-bytediff-1.0.0.tgz", - "integrity": "sha1-VXPidyiwsW1cqIaU/NNhYzj5xS0=", - "requires": { - "filesize": "~3.1.3", - "gulp-util": "~3.0.6", - "map-stream": "~0.0.6" - } - }, - "gulp-if": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-3.0.0.tgz", - "integrity": "sha512-fCUEngzNiEZEK2YuPm+sdMpO6ukb8+/qzbGfJBXyNOXz85bCG7yBI+pPSl+N90d7gnLvMsarthsAImx0qy7BAw==", - "requires": { - "gulp-match": "^1.1.0", - "ternary-stream": "^3.0.0", - "through2": "^3.0.1" - }, - "dependencies": { - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "requires": { - "readable-stream": "2 || 3" - } - } - } - }, - "gulp-load-plugins": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/gulp-load-plugins/-/gulp-load-plugins-1.6.0.tgz", - "integrity": "sha512-HlCODki0WHJvQIgAsJYOTkyo0c7TsDCetvfhrdGz9JYPL6A4mFRMGmKfoi6JmXjA/vvzg+fkT91c9FBh7rnkyg==", - "requires": { - "array-unique": "^0.2.1", - "fancy-log": "^1.2.0", - "findup-sync": "^3.0.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "micromatch": "^3.1.10", - "resolve": "^1.1.7" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - } - } - } - } - }, - "gulp-match": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.1.0.tgz", - "integrity": "sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==", - "requires": { - "minimatch": "^3.0.3" - } - }, - "gulp-postcss": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/gulp-postcss/-/gulp-postcss-6.1.0.tgz", - "integrity": "sha1-ZjnZKJrzA1qIsB6fp2RvhcJKFMY=", - "requires": { - "gulp-util": "^3.0.7", - "postcss": "^5.0.14", - "vinyl-sourcemaps-apply": "^0.2.0" - }, - "dependencies": { - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - } - } - } - }, - "gulp-size": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gulp-size/-/gulp-size-2.0.0.tgz", - "integrity": "sha1-UHYCbShf+qBNyPqQRFoLPjZT0TQ=", - "requires": { - "chalk": "^1.0.0", - "gulp-util": "^3.0.0", - "gzip-size": "^3.0.0", - "pretty-bytes": "^2.0.1", - "stream-counter": "^1.0.0", - "through2": "^2.0.0" - } - }, - "gulp-sourcemaps": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz", - "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=", - "requires": { - "convert-source-map": "^1.1.1", - "graceful-fs": "^4.1.2", - "strip-bom": "^2.0.0", - "through2": "^2.0.0", - "vinyl": "^1.0.0" - } - }, - "gulp-stylus": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/gulp-stylus/-/gulp-stylus-2.7.0.tgz", - "integrity": "sha512-LlneLeHcaRBaEqxwo5YCirpsfkR7uleQ4pHXW8IE2ZeA6M3jpgI90+zQ6SptMTSWr1RSQW3WYFZVA3P0coUojw==", - "requires": { - "accord": "^0.26.3", - "lodash.assign": "^3.2.0", - "plugin-error": "^0.1.2", - "replace-ext": "0.0.1", - "stylus": "^0.54.0", - "through2": "^2.0.0", - "vinyl-sourcemaps-apply": "^0.2.0" - }, - "dependencies": { - "glob": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", - "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "sax": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", - "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=" - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "requires": { - "amdefine": ">=0.0.4" - } - }, - "stylus": { - "version": "0.54.5", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", - "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", - "requires": { - "css-parse": "1.7.x", - "debug": "*", - "glob": "7.0.x", - "mkdirp": "0.5.x", - "sax": "0.5.x", - "source-map": "0.1.x" - } - } - } - }, - "gulp-uglify": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz", - "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==", - "requires": { - "array-each": "^1.0.1", - "extend-shallow": "^3.0.2", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "isobject": "^3.0.1", - "make-error-cause": "^1.1.1", - "safe-buffer": "^5.1.2", - "through2": "^2.0.0", - "uglify-js": "^3.0.5", - "vinyl-sourcemaps-apply": "^0.2.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", - "requires": { - "commander": "~2.20.0", - "source-map": "~0.6.1" - } - } - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "dependencies": { - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" - }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "requires": { - "glogg": "^1.0.0" - } - }, - "gzip-size": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", - "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", - "requires": { - "duplexer": "^0.1.1" - } - }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "requires": { - "function-bind": "^1.0.2" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "requires": { - "sparkles": "^1.0.0" - } - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hosted-git-info": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==" - }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=" - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" - }, - "html-comment-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", - "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" - }, - "html5shiv": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/html5shiv/-/html5shiv-3.7.3.tgz", - "integrity": "sha1-14qEo2e8uacQEA1XgCw4ewhGMdI=" - }, - "htmlescape": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" - }, - "https-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", - "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=" - }, - "ie8": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/ie8/-/ie8-0.8.1.tgz", - "integrity": "sha512-DaDrZvCFXE3fRc1THFU1BQqWmdp9OPMFLgupv3DWq92T1jvty1EtwpDQmeovkylm+1pieaSmkxKahNL8H4T8+w==" - }, - "ieee754": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", - "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==" - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "requires": { - "requester-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "requires": { - "repeating": "^2.0.0" - } - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, - "indx": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/indx/-/indx-0.2.3.tgz", - "integrity": "sha1-Fdz1bunPZcAjTFE8J/vVgOcPvFA=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "inline-source-map": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", - "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", - "requires": { - "source-map": "~0.5.3" - } - }, - "insert-module-globals": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.1.0.tgz", - "integrity": "sha512-LbYZdybvKjbbcKLp03lB323Cgc8f0iL0Rjh8U6JZ7K1gZSf7MxQH191iCNUcLX4qIQ6/yWe4Q4ZsQ+opcReNFg==", - "requires": { - "JSONStream": "^1.0.3", - "combine-source-map": "^0.8.0", - "concat-stream": "^1.6.1", - "is-buffer": "^1.1.0", - "lexical-scope": "^1.2.0", - "path-is-absolute": "^1.0.1", - "process": "~0.11.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - } - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" - }, - "is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "requires": { - "has": "^1.0.1" - } - }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "requires": { - "is-unc-path": "^1.0.0" - } - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" - }, - "is-svg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", - "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", - "requires": { - "html-comment-regex": "^1.1.0" - } - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", - "requires": { - "unc-path-regex": "^0.1.2" - } - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - }, - "is-valid-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=" - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "js-base64": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.5.tgz", - "integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ==" - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - } - } - }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" - }, - "jstransform": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-3.0.0.tgz", - "integrity": "sha1-olkats7o2XvzvoMNv6IxO4fNZAs=", - "requires": { - "base62": "0.1.1", - "esprima-fb": "~3001.1.0-dev-harmony-fb", - "source-map": "0.1.31" - }, - "dependencies": { - "esprima-fb": { - "version": "3001.1.0-dev-harmony-fb", - "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-3001.0001.0000-dev-harmony-fb.tgz", - "integrity": "sha1-t303q8046gt3Qmu4vCkizmtCZBE=" - }, - "source-map": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz", - "integrity": "sha1-n3BNDWnZ4TioG63267T94z0VHGE=", - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "just-debounce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", - "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "labeled-stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", - "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", - "requires": { - "inherits": "^2.0.1", - "isarray": "^2.0.4", - "stream-splicer": "^2.0.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==" - } - } - }, - "last-run": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", - "requires": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" - } - }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" - }, - "lazystream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "requires": { - "readable-stream": "^2.0.5" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "^1.0.0" - } - }, - "lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", - "requires": { - "flush-write-stream": "^1.0.2" - } - }, - "lexical-scope": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", - "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=", - "requires": { - "astw": "^2.0.0" - } - }, - "liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "requires": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=" - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=" - }, - "lodash._bindcallback": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=" - }, - "lodash._createassigner": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", - "integrity": "sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=", - "requires": { - "lodash._bindcallback": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash.restparam": "^3.0.0" - } - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=" - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=" - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" - }, - "lodash.assign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", - "integrity": "sha1-POnwI0tLIiPilrj6CsH+6OvKZPo=", - "requires": { - "lodash._baseassign": "^3.0.0", - "lodash._createassigner": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "lodash.clone": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=" - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" - }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "requires": { - "lodash._root": "^3.0.0" - } - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "lodash.partialright": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.partialright/-/lodash.partialright-4.2.1.tgz", - "integrity": "sha1-ATDYDoM2MmTUAHTzKbij56ihzEs=" - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" - }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "^3.0.0" - } - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } - }, - "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==" - }, - "make-error-cause": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz", - "integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=", - "requires": { - "make-error": "^1.2.0" - } - }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" - } - }, - "matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", - "requires": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "dependencies": { - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "mdn-data": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", - "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==" - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } - } - }, - "modify-babel-preset": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/modify-babel-preset/-/modify-babel-preset-1.2.0.tgz", - "integrity": "sha1-0bfIwkiW4Z28SEc0chPmtxRNG8c=", - "requires": { - "require-relative": "^0.8.7" - } - }, - "module-deps": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz", - "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=", - "requires": { - "JSONStream": "^1.0.3", - "browser-resolve": "^1.7.0", - "cached-path-relative": "^1.0.0", - "concat-stream": "~1.5.0", - "defined": "^1.0.0", - "detective": "^4.0.0", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.3", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - } - } - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "requires": { - "duplexer2": "0.0.2" - }, - "dependencies": { - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "requires": { - "readable-stream": "~1.1.9" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==" - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node-releases": { - "version": "1.1.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.23.tgz", - "integrity": "sha512-uq1iL79YjfYC0WXoHbC/z28q/9pOl8kSHaXdWmAAc8No+bDwqkZbzIJz55g/MUsPgSGm9LZ7QSUbzTcH5tz47w==", - "requires": { - "semver": "^5.3.0" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" - }, - "normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" - }, - "now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", - "requires": { - "once": "^1.3.2" - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { - "boolbase": "~1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" - }, - "dependencies": { - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - } - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "onecolor": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/onecolor/-/onecolor-2.4.2.tgz", - "integrity": "sha1-pT7D/xccNEYBbdUhDRobVEv32HQ=" - }, - "ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", - "requires": { - "readable-stream": "^2.0.1" - } - }, - "os-browserify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz", - "integrity": "sha1-ScoCk+CxlZCl9d4Qx/JlphfY/lQ=" - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "requires": { - "lcid": "^1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "outpipe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz", - "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=", - "requires": { - "shell-quote": "^1.4.2" - } - }, - "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" - }, - "parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", - "requires": { - "path-platform": "~0.11.15" - } - }, - "parse-asn1": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", - "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" - } - }, - "parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "^1.2.0" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=" - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" - }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "requires": { - "path-root-regex": "^0.1.0" - } - }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "paths-js": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/paths-js/-/paths-js-0.4.10.tgz", - "integrity": "sha512-JZoqlRSHtx+bc+xKI9o4bropEbqZBF4ZfYImiB1T9RYpHB73h5I8XZ7FfSBbHbBMtdD1c04ujjAPH8wUuu4+Gw==" - }, - "pbkdf2": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", - "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - } - }, - "pleeease-filters": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pleeease-filters/-/pleeease-filters-2.0.0.tgz", - "integrity": "sha1-tk3M+y3AjXNDSyM8pmCrDw87quo=", - "requires": { - "onecolor": "~2.4.0", - "postcss": "^5.0.4" - }, - "dependencies": { - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - } - } - } - }, - "plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "requires": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - }, - "dependencies": { - "arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "requires": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - } - }, - "arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=" - }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=" - }, - "extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "requires": { - "kind-of": "^1.1.0" - } - }, - "kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=" - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, - "postcss": { - "version": "7.0.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.18.tgz", - "integrity": "sha512-/7g1QXXgegpF+9GJj4iN7ChGF40sYuGYJ8WZu8DZWnmhQ/G36hfdk3q9LBJmoK+lZ+yzZ5KYpOoxq7LF1BxE8g==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-calc": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", - "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", - "requires": { - "css-unit-converter": "^1.1.1", - "postcss": "^7.0.5", - "postcss-selector-parser": "^5.0.0-rc.4", - "postcss-value-parser": "^3.3.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-color-rgba-fallback": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-color-rgba-fallback/-/postcss-color-rgba-fallback-2.2.0.tgz", - "integrity": "sha1-bSlJG+WZCpMXPUfnx29YELCUAro=", - "requires": { - "postcss": "^5.0.0", - "postcss-value-parser": "^3.0.2", - "rgb-hex": "^1.0.0" - }, - "dependencies": { - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - } - } - } - }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "browserslist": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.2.tgz", - "integrity": "sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==", - "requires": { - "caniuse-lite": "^1.0.30000974", - "electron-to-chromium": "^1.3.150", - "node-releases": "^1.1.23" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "electron-to-chromium": { - "version": "1.3.163", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.163.tgz", - "integrity": "sha512-uCEoqQeKrjlhUSUudY0XvyNVDhWR5XmnCIV0WXr2Qo9PVzEVXI75LHGtzwro9Qh8NNetRjSitrm8AfQvPGaSqA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-filter-gradient": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/postcss-filter-gradient/-/postcss-filter-gradient-0.2.2.tgz", - "integrity": "sha1-261119xWoNYH/W6HNjCCtCyaWGA=", - "requires": { - "filter-gradient": "^1.0.1", - "postcss": "^5.0.2" - }, - "dependencies": { - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - } - } - } - }, - "postcss-font-weights": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-font-weights/-/postcss-font-weights-2.0.1.tgz", - "integrity": "sha1-qF3XtRqnaRuVybwCafQSdWyRkx0=", - "requires": { - "css-font-weight-names": "^0.2.1", - "postcss": "^5.0.12" - }, - "dependencies": { - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - } - } - } - }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "browserslist": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.2.tgz", - "integrity": "sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==", - "requires": { - "caniuse-lite": "^1.0.30000974", - "electron-to-chromium": "^1.3.150", - "node-releases": "^1.1.23" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "electron-to-chromium": { - "version": "1.3.163", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.163.tgz", - "integrity": "sha512-uCEoqQeKrjlhUSUudY0XvyNVDhWR5XmnCIV0WXr2Qo9PVzEVXI75LHGtzwro9Qh8NNetRjSitrm8AfQvPGaSqA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "browserslist": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.2.tgz", - "integrity": "sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==", - "requires": { - "caniuse-lite": "^1.0.30000974", - "electron-to-chromium": "^1.3.150", - "node-releases": "^1.1.23" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "electron-to-chromium": { - "version": "1.3.163", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.163.tgz", - "integrity": "sha512-uCEoqQeKrjlhUSUudY0XvyNVDhWR5XmnCIV0WXr2Qo9PVzEVXI75LHGtzwro9Qh8NNetRjSitrm8AfQvPGaSqA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "browserslist": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.2.tgz", - "integrity": "sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==", - "requires": { - "caniuse-lite": "^1.0.30000974", - "electron-to-chromium": "^1.3.150", - "node-releases": "^1.1.23" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "electron-to-chromium": { - "version": "1.3.163", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.163.tgz", - "integrity": "sha512-uCEoqQeKrjlhUSUudY0XvyNVDhWR5XmnCIV0WXr2Qo9PVzEVXI75LHGtzwro9Qh8NNetRjSitrm8AfQvPGaSqA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-opacity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-opacity/-/postcss-opacity-5.0.0.tgz", - "integrity": "sha512-n6LgHk5HWIsyEHgPqM2jwXrkh4SuH+cZOIWh4tUp4ug3P7FkzxiJuqrpEaBvNwH/dKs5PHjHL2vPeR+nLbs+Mw==", - "requires": { - "postcss": "^6.0.7" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "browserslist": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.2.tgz", - "integrity": "sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==", - "requires": { - "caniuse-lite": "^1.0.30000974", - "electron-to-chromium": "^1.3.150", - "node-releases": "^1.1.23" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "electron-to-chromium": { - "version": "1.3.163", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.163.tgz", - "integrity": "sha512-uCEoqQeKrjlhUSUudY0XvyNVDhWR5XmnCIV0WXr2Qo9PVzEVXI75LHGtzwro9Qh8NNetRjSitrm8AfQvPGaSqA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "postcss-svgo": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", - "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", - "requires": { - "is-svg": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", - "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=" - }, - "pretty-bytes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-2.0.1.tgz", - "integrity": "sha1-FV7E0ANvQTkecEXW2+SWPVJdJk8=", - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.1.0", - "number-is-nan": "^1.0.0" - } - }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "public-encrypt": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", - "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" - }, - "ractive": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/ractive/-/ractive-0.7.3.tgz", - "integrity": "sha1-RHguX0nVsdj/1EL9uWSzW3HgEJs=" - }, - "ractive-componentify": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/ractive-componentify/-/ractive-componentify-0.2.4.tgz", - "integrity": "sha1-g/0XRtuKXW/NabrZSVwUhoKFcM0=", - "requires": { - "es6-promise": "^2.0.1", - "through": "^2.3.6", - "vlq": "^0.2.1" - } - }, - "ractive-events-keys": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ractive-events-keys/-/ractive-events-keys-0.2.1.tgz", - "integrity": "sha1-ra4wLoxPTKKLkSdJReekBpgWB1E=" - }, - "ractive-transitions-fade": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/ractive-transitions-fade/-/ractive-transitions-fade-0.3.1.tgz", - "integrity": "sha1-IF0pnmzaRjfiKGGYzWn3bAnk0wY=" - }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", - "requires": { - "readable-stream": "^2.0.2" - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "requires": { - "resolve": "^1.1.6" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - } - }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - } - } - }, - "remove-bom-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", - "requires": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" - } - }, - "remove-bom-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", - "requires": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "^1.0.0" - } - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" - }, - "replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", - "requires": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-globify": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/require-globify/-/require-globify-1.3.0.tgz", - "integrity": "sha1-b5E4Sutx6UKSP9zj9L5VwU2G1R0=", - "requires": { - "browserify-transform-tools": "^1.4.2", - "glob": "^5.0.14" - } - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "require-relative": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", - "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=" - }, - "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "requires": { - "path-parse": "^1.0.5" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" - }, - "resolve-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", - "requires": { - "value-or-function": "^3.0.0" - } - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "rgb-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgb-hex/-/rgb-hex-1.0.0.tgz", - "integrity": "sha1-v6+M2c2RZLWibXHrTxWgllMks8E=" - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" - }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "requires": { - "align-text": "^0.1.1" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, - "semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", - "requires": { - "sver-compat": "^1.5.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shasum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", - "requires": { - "json-stable-stringify": "~0.0.0", - "sha.js": "~2.4.4" - } - }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - } - } - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "^0.5.6" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" - }, - "sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==" - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "requires": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "stream-counter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-1.0.0.tgz", - "integrity": "sha1-kc8lac5NxQYf6816yyY5SloRR1E=" - }, - "stream-exhaust": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==" - }, - "stream-http": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.2.tgz", - "integrity": "sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==", - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "stream-splicer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", - "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "requires": { - "get-stdin": "^4.0.1" - } - }, - "stylehacks": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "browserslist": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.2.tgz", - "integrity": "sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==", - "requires": { - "caniuse-lite": "^1.0.30000974", - "electron-to-chromium": "^1.3.150", - "node-releases": "^1.1.23" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "electron-to-chromium": { - "version": "1.3.163", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.163.tgz", - "integrity": "sha512-uCEoqQeKrjlhUSUudY0XvyNVDhWR5XmnCIV0WXr2Qo9PVzEVXI75LHGtzwro9Qh8NNetRjSitrm8AfQvPGaSqA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "stylus": { - "version": "0.54.7", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.7.tgz", - "integrity": "sha512-Yw3WMTzVwevT6ZTrLCYNHAFmanMxdylelL3hkWNgPMeTCpMwpV3nXjpOHuBXtFv7aiO2xRuQS6OoAdgkNcSNug==", - "requires": { - "css-parse": "~2.0.0", - "debug": "~3.1.0", - "glob": "^7.1.3", - "mkdirp": "~0.5.x", - "safer-buffer": "^2.1.2", - "sax": "~1.2.4", - "semver": "^6.0.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "css-parse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", - "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", - "requires": { - "css": "^2.0.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } - } - }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", - "requires": { - "minimist": "^1.1.0" - } - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "requires": { - "has-flag": "^1.0.0" - } - }, - "sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", - "requires": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, - "svgo": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.2.2.tgz", - "integrity": "sha512-rAfulcwp2D9jjdGu+0CuqlrAUin6bBWrpoqXWwKDZZZJfXcUXQSxLJOFJCQCSA0x0pP2U0TxSlJu2ROq5Bq6qA==", - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.28", - "css-url-regex": "^1.1.0", - "csso": "^3.5.1", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "requires": { - "acorn-node": "^1.2.0" - } - }, - "ternary-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-3.0.0.tgz", - "integrity": "sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ==", - "requires": { - "duplexify": "^4.1.1", - "fork-stream": "^0.0.4", - "merge-stream": "^2.0.0", - "through2": "^3.0.1" - }, - "dependencies": { - "duplexify": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", - "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "requires": { - "readable-stream": "2 || 3" - } - } - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - }, - "through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - } - }, - "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" - }, - "timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", - "requires": { - "process": "~0.11.0" - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" - }, - "to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", - "requires": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - } - } - } - }, - "to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", - "requires": { - "through2": "^2.0.3" - } - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" - }, - "tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" - }, - "type": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/type/-/type-1.0.1.tgz", - "integrity": "sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw==" - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "optional": true - }, - "umd": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==" - }, - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" - }, - "undertaker": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", - "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", - "requires": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" - } - }, - "undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=" - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" - }, - "unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", - "requires": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" - } - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - } - } - }, - "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==" - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "v8flags": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", - "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=" - }, - "vendors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.3.tgz", - "integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==" - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.1.tgz", - "integrity": "sha1-lsGjR5uMU5JULGEgKQE7Wyf4i78=", - "requires": { - "bl": "^1.2.1", - "through2": "^2.0.3" - } - }, - "vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", - "requires": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" - }, - "dependencies": { - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" - }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" - }, - "vinyl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", - "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - } - } - }, - "vinyl-source-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz", - "integrity": "sha1-84pa+53R6Ttl1VBGmsYYKsT1S44=", - "requires": { - "through2": "^2.0.3", - "vinyl": "^2.1.0" - }, - "dependencies": { - "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=" - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" - }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" - }, - "vinyl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", - "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - } - } - }, - "vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", - "requires": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" - }, - "dependencies": { - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" - }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" - }, - "vinyl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", - "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - } - } - }, - "vinyl-sourcemaps-apply": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", - "requires": { - "source-map": "^0.5.1" - } - }, - "vlq": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", - "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" - }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "requires": { - "indexof": "0.0.1" - } - }, - "watchify": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.11.1.tgz", - "integrity": "sha512-WwnUClyFNRMB2NIiHgJU9RQPQNqVeFk7OmZaWf5dC5EnNa0Mgr7imBydbaJ7tGTuPM2hz1Cb4uiBvK9NVxMfog==", - "requires": { - "anymatch": "^2.0.0", - "browserify": "^16.1.0", - "chokidar": "^2.1.1", - "defined": "^1.0.0", - "outpipe": "^1.1.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==" - }, - "acorn-node": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.7.0.tgz", - "integrity": "sha512-XhahLSsCB6X6CJbe+uNu3Mn9sJBNFxtBN9NLgAOQovfS6Kh0lDUtmlclhjn9CvEK7A7YyRU13PXlNcpSiLI9Yw==", - "requires": { - "acorn": "^6.1.1", - "acorn-dynamic-import": "^4.0.0", - "acorn-walk": "^6.1.1", - "xtend": "^4.0.1" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "browserify": { - "version": "16.2.3", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz", - "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==", - "requires": { - "JSONStream": "^1.0.3", - "assert": "^1.4.0", - "browser-pack": "^6.0.1", - "browser-resolve": "^1.11.0", - "browserify-zlib": "~0.2.0", - "buffer": "^5.0.2", - "cached-path-relative": "^1.0.0", - "concat-stream": "^1.6.0", - "console-browserify": "^1.1.0", - "constants-browserify": "~1.0.0", - "crypto-browserify": "^3.0.0", - "defined": "^1.0.0", - "deps-sort": "^2.0.0", - "domain-browser": "^1.2.0", - "duplexer2": "~0.1.2", - "events": "^2.0.0", - "glob": "^7.1.0", - "has": "^1.0.0", - "htmlescape": "^1.1.0", - "https-browserify": "^1.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^7.0.0", - "labeled-stream-splicer": "^2.0.0", - "mkdirp": "^0.5.0", - "module-deps": "^6.0.0", - "os-browserify": "~0.3.0", - "parents": "^1.0.1", - "path-browserify": "~0.0.0", - "process": "~0.11.0", - "punycode": "^1.3.2", - "querystring-es3": "~0.2.0", - "read-only-stream": "^2.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.4", - "shasum": "^1.0.0", - "shell-quote": "^1.6.1", - "stream-browserify": "^2.0.0", - "stream-http": "^2.0.0", - "string_decoder": "^1.1.1", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^2.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "0.0.1", - "url": "~0.11.0", - "util": "~0.10.1", - "vm-browserify": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { - "pako": "~1.0.5" - } - }, - "buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - } - } - }, - "detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", - "requires": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" - }, - "events": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", - "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==" - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "module-deps": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.1.tgz", - "integrity": "sha512-UnEn6Ah36Tu4jFiBbJVUtt0h+iXqxpLqDvPS8nllbw5RZFmNJ1+Mz5BjYnM9ieH80zyxHkARGLnMIHlPK5bu6A==", - "requires": { - "JSONStream": "^1.0.3", - "browser-resolve": "^1.7.0", - "cached-path-relative": "^1.0.2", - "concat-stream": "~1.6.0", - "defined": "^1.0.0", - "detective": "^5.0.2", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.4.0", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" - }, - "pako": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "vm-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", - "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==" - } - } - }, - "when": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", - "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - }, - "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "requires": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-requester-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - } - } - }, - "yargs-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", - "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "requires": { - "camelcase": "^3.0.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - } - } - } - } -} diff --git a/tgui/package.json b/tgui/package.json index dd81c3b3180..208b9001305 100644 --- a/tgui/package.json +++ b/tgui/package.json @@ -1,67 +1,31 @@ { - "name": "tgui", - "private": true, - "scripts": { - "build": "gulp --min", - "watch": "gulp watch" - }, - "dependencies": { - "autoprefixer": "6.7.7", - "babel-core": "6.26.3", - "babel-plugin-external-helpers": "6.22.0", - "babel-polyfill": "6.26.0", - "babel-preset-es2015": "6.24.1", - "babel-preset-es2015-loose": "7.0.0", - "babel-register": "6.26.0", - "babelify": "7.2.0", - "babelify-external-helpers": "1.1.0", - "browserify": "13.0.0", - "bundle-collapser": "1.2.1", - "cached-path-relative": "1.0.2", - "cssnano": "^4.1.10", - "dom4": "1.7.0", - "es3ify": "0.2.1", - "fg-loadcss": "1.0.0-0", - "gulp": "^4.0.2", - "gulp-bytediff": "1.0.0", - "gulp-if": "3.0.0", - "gulp-load-plugins": "^1.6.0", - "gulp-postcss": "6.1.0", - "gulp-size": "2.0.0", - "gulp-sourcemaps": "1.6.0", - "gulp-stylus": "2.7.0", - "gulp-uglify": "3.0.2", - "gulplog": "1.0.0", - "html5shiv": "3.7.3", - "ie8": "0.8.1", - "lodash": "^4.17.15", - "minimist": "1.2.0", - "paths-js": "0.4.10", - "pleeease-filters": "2.0.0", - "postcss": "7.0.18", - "postcss-color-rgba-fallback": "2.2.0", - "postcss-filter-gradient": "0.2.2", - "postcss-font-weights": "2.0.1", - "postcss-opacity": "5.0.0", - "ractive": "0.7.3", - "ractive-componentify": "0.2.4", - "ractive-events-keys": "0.2.1", - "ractive-transitions-fade": "0.3.1", - "require-globify": "1.3.0", - "stylus": "0.54.7", - "vinyl-buffer": "1.0.1", - "vinyl-source-stream": "2.0.0", - "watchify": "^3.11.1" - }, - "browser": { - "ractive": "ractive/ractive-legacy.runtime" - }, - "require-globify": { - "appliesTo": { - "includeExtensions": [ - ".js", - ".ract" - ] - } - } + "name": "tgui-workspace", + "version": "6.0.0", + "devDependencies": { + "@happy-dom/global-registrator": "^20.0.11", + "@rspack/cli": "^1.6.8", + "@rspack/core": "^1.6.8", + "@testing-library/react": "^16.3.2", + "@types/bun": "^1.3.5", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "@types/webpack-env": "^1.18.8", + "@types/wicg-file-system-access": "^2023.10.6", + "css-loader": "^7.1.2", + "sass-embedded": "^1.97.1", + "sass-loader": "^16.0.6", + "typescript": "^5.8.3" + }, + "packageManager": "bun@1.2.16", + "private": true, + "scripts": { + "tgui:analyze": "rspack --analyze", + "tgui:build": "rspack build", + "tgui:dev": "bun --smol packages/tgui-dev-server/index.ts", + "tgui:test": "bun test", + "tgui:tsc": "tsc" + }, + "workspaces": [ + "packages/*" + ] } diff --git a/tgui/packages/common/assets.ts b/tgui/packages/common/assets.ts new file mode 100644 index 00000000000..958d472ca4e --- /dev/null +++ b/tgui/packages/common/assets.ts @@ -0,0 +1,30 @@ +const EXCLUDED_PATTERNS = [/v4shim/i]; + +export function loadStyleSheet(payload: string): void { + Byond.loadCss(payload); +} + +export function loadMappings( + payload: Record, + /** Lets you insert your own independent asset map. */ + map: Record, +): void { + for (const name in payload) { + // Skip anything that matches excluded patterns + if (EXCLUDED_PATTERNS.some((regex) => regex.test(name))) { + continue; + } + + const url = payload[name]; + const ext = name.split('.').pop(); + + map[name] = url; + + if (ext === 'css') { + Byond.loadCss(url); + } + if (ext === 'js') { + Byond.loadJs(url); + } + } +} diff --git a/tgui/packages/common/collections.ts b/tgui/packages/common/collections.ts new file mode 100644 index 00000000000..438ad19a4d2 --- /dev/null +++ b/tgui/packages/common/collections.ts @@ -0,0 +1,50 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +const binarySearch = ( + getKey: (value: T) => U, + collection: readonly T[], + inserting: T, +): number => { + if (collection.length === 0) { + return 0; + } + + const insertingKey = getKey(inserting); + + let [low, high] = [0, collection.length]; + + // Because we have checked if the collection is empty, it's impossible + // for this to be used before assignment. + let compare: U = undefined as unknown as U; + let middle = 0; + + while (low < high) { + middle = (low + high) >> 1; + + compare = getKey(collection[middle]); + + if (compare < insertingKey) { + low = middle + 1; + } else if (compare === insertingKey) { + return middle; + } else { + high = middle; + } + } + + return compare > insertingKey ? middle : middle + 1; +}; + +export const binaryInsertWith = ( + collection: readonly T[], + value: T, + getKey: (value: T) => U, +): T[] => { + const copy = [...collection]; + copy.splice(binarySearch(getKey, collection, value), 0, value); + return copy; +}; diff --git a/tgui/packages/common/package.json b/tgui/packages/common/package.json new file mode 100644 index 00000000000..c5419a7a6d2 --- /dev/null +++ b/tgui/packages/common/package.json @@ -0,0 +1,9 @@ +{ + "name": "common", + "version": "4.3.1", + "dependencies": { + "es-toolkit": "^1.43.0", + "zod": "^4.2.0" + }, + "private": true +} diff --git a/tgui/packages/common/perf.ts b/tgui/packages/common/perf.ts new file mode 100644 index 00000000000..a7dfefc1e1c --- /dev/null +++ b/tgui/packages/common/perf.ts @@ -0,0 +1,72 @@ +/** + * Ghetto performance measurement tools. + * + * Uses NODE_ENV to remove itself from production builds. + * + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +const FPS = 60; +const FRAME_DURATION = 1000 / FPS; + +// True if Performance API is supported +const supportsPerf = !!window.performance?.now; +// High precision markers +const hpMarkersByName: Record = {}; +// Low precision markers +const lpMarkersByName: Record = {}; + +/** + * Marks a certain spot in the code for later measurements. + */ +function mark(name: string, timestamp?: number): void { + if (process.env.NODE_ENV !== 'production') { + if (supportsPerf && !timestamp) { + hpMarkersByName[name] = performance.now(); + } + lpMarkersByName[name] = timestamp || Date.now(); + } +} + +/** + * Calculates and returns the difference between two markers as a string. + * + * Use logger.log() to print the measurement. + */ +function measure(markerNameA: string, markerNameB: string): string | undefined { + if (process.env.NODE_ENV === 'production') return; + + let markerA = hpMarkersByName[markerNameA]; + let markerB = hpMarkersByName[markerNameB]; + + if (!markerA || !markerB) { + markerA = lpMarkersByName[markerNameA]; + markerB = lpMarkersByName[markerNameB]; + } + + const duration = Math.abs(markerB - markerA); + + return formatDuration(duration); +} + +/** + * Formats a duration in milliseconds and frames. + */ +function formatDuration(duration: number): string { + const durationInFrames = duration / FRAME_DURATION; + + return ( + duration.toFixed(duration < 10 ? 1 : 0) + + 'ms ' + + '(' + + durationInFrames.toFixed(2) + + ' frames)' + ); +} + +export const perf = { + mark, + measure, +}; diff --git a/tgui/packages/common/storage.ts b/tgui/packages/common/storage.ts new file mode 100644 index 00000000000..1955fa8ab8e --- /dev/null +++ b/tgui/packages/common/storage.ts @@ -0,0 +1,229 @@ +/** + * Browser-agnostic abstraction of key-value web storage. + * + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +export const IMPL_HUB_STORAGE = 1; +export const IMPL_IFRAME_INDEXED_DB = 2; + +type StorageImplementation = + | typeof IMPL_HUB_STORAGE + | typeof IMPL_IFRAME_INDEXED_DB; + +type StorageBackend = { + impl: StorageImplementation; + get(key: string): Promise; + set(key: string, value: any): Promise; + remove(key: string): Promise; + clear(): Promise; +}; + +const testGeneric = (testFn: () => boolean) => (): boolean => { + try { + return Boolean(testFn()); + } catch { + return false; + } +}; + +const testHubStorage = testGeneric( + () => window.hubStorage && !!window.hubStorage.getItem, +); + +class HubStorageBackend implements StorageBackend { + public impl: StorageImplementation; + + constructor() { + this.impl = IMPL_HUB_STORAGE; + } + + async get(key: string): Promise { + const value = await window.hubStorage.getItem(key); + if (typeof value === 'string') { + return JSON.parse(value); + } + return undefined; + } + + async set(key: string, value: any): Promise { + window.hubStorage.setItem(key, JSON.stringify(value)); + } + + async remove(key: string): Promise { + window.hubStorage.removeItem(key); + } + + async clear(): Promise { + window.hubStorage.clear(); + } +} + +class IFrameIndexedDbBackend implements StorageBackend { + public impl: StorageImplementation; + + private documentElement: HTMLIFrameElement; + private iframeWindow: Window; + + constructor() { + this.impl = IMPL_IFRAME_INDEXED_DB; + } + + async ready(): Promise { + const iframe = document.createElement('iframe'); + iframe.style.display = 'none'; + iframe.src = Byond.storageCdn; + + const completePromise: Promise = new Promise((resolve) => { + fetch(Byond.storageCdn, { method: "HEAD" }).then((response) => { + if (response.status !== 200) { + resolve(false); + } + + }).catch(() => { + resolve(false); + }) + + window.addEventListener('message', (message) => { + if (message.data === "ready") { + resolve(true); + } + }) + }); + + this.documentElement = document.body.appendChild(iframe); + if (!this.documentElement.contentWindow) { + return new Promise((res) => res(false)); + } + + this.iframeWindow = this.documentElement.contentWindow; + + return completePromise; + } + + async get(key: string): Promise { + const promise = new Promise((resolve) => { + window.addEventListener('message', (message) => { + if (message.data.key && message.data.key === key) { + resolve(message.data.value); + } + }); + }); + + this.iframeWindow.postMessage({ type: 'get', key: key }, '*'); + return promise; + } + + async set(key: string, value: any): Promise { + this.iframeWindow.postMessage({ type: 'set', key: key, value: value }, '*'); + } + + async remove(key: string): Promise { + this.iframeWindow.postMessage({ type: 'remove', key: key }, '*'); + } + + async clear(): Promise { + this.iframeWindow.postMessage({ type: 'clear' }, '*'); + } + + async destroy(): Promise { + document.body.removeChild(this.documentElement); + } +} + +/** + * Web Storage Proxy object, which selects the best backend available + * depending on the environment. + */ +class StorageProxy implements StorageBackend { + private backendPromise: Promise; + public impl: StorageImplementation = IMPL_IFRAME_INDEXED_DB; + + constructor() { + this.backendPromise = (async () => { + + // If we have not enabled byondstorage yet, we need to check + // if we can use the IFrame, or if we need to enable byondstorage + if (!testHubStorage()) { + + // If we have an IFrame URL we can use, and we haven't already enabled + // byondstorage, we should use the IFrame backend + if (Byond.storageCdn) { + const iframe = new IFrameIndexedDbBackend(); + + if ((await iframe.ready()) === true) { + if (await iframe.get('byondstorage-migrated')) return iframe; + + Byond.winset(null, 'browser-options', '+byondstorage'); + + await new Promise((resolve) => { + document.addEventListener('byondstorageupdated', async () => { + setTimeout(() => { + const hub = new HubStorageBackend(); + + // Migrate these existing settings from byondstorage to the IFrame + for (const setting of ['panel-settings', 'chat-state', 'chat-messages']) { + hub + .get(setting) + .then((settings) => iframe.set(setting, settings)); + } + + iframe.set('byondstorage-migrated', true); + Byond.winset(null, 'browser-options', '-byondstorage'); + + resolve(); + }, 1); + }); + }); + + return iframe; + } + + iframe.destroy(); + }; + + // IFrame hasn't worked out for us, we'll need to enable byondstorage + Byond.winset(null, 'browser-options', '+byondstorage'); + + return new Promise((resolve) => { + const listener = () => { + document.removeEventListener('byondstorageupdated', listener); + + // This event is emitted *before* byondstorage is actually created + // so we have to wait a little bit before we can use it + setTimeout(() => resolve(new HubStorageBackend()), 1); + }; + + document.addEventListener('byondstorageupdated', listener); + }); + } + + // byondstorage is already enabled, we can use it straight away + return new HubStorageBackend(); + })(); + } + + async get(key: string): Promise { + const backend = await this.backendPromise; + return backend.get(key); + } + + async set(key: string, value: any): Promise { + const backend = await this.backendPromise; + return backend.set(key, value); + } + + async remove(key: string): Promise { + const backend = await this.backendPromise; + return backend.remove(key); + } + + async clear(): Promise { + const backend = await this.backendPromise; + return backend.clear(); + } +} + +export const storage = new StorageProxy(); diff --git a/tgui/packages/common/type-safety.test.ts b/tgui/packages/common/type-safety.test.ts new file mode 100644 index 00000000000..f572a19781d --- /dev/null +++ b/tgui/packages/common/type-safety.test.ts @@ -0,0 +1,53 @@ +import { describe, it } from 'bun:test'; +import assert from 'node:assert/strict'; +import * as z from 'zod'; +import { smoothMerge } from './type-safety'; + +describe('smoothMerge', () => { + it('merges valid fields from source into target', () => { + const schema = z.object({ + a: z.string(), + b: z.number(), + }); + + const source = { a: 'hello', b: 'not a number', c: true }; + const target = { a: 'default', b: 42 }; + + const result = smoothMerge({ schema, source, target }); + assert.deepEqual(result, { a: 'hello', b: 42 }); + }); + + it('returns target if source is empty', () => { + const schema = z.object({ + a: z.string(), + }); + + const source = {}; + const target = { a: 'default' }; + const result = smoothMerge({ schema, source, target }); + assert.deepEqual(result, target); + }); + + it('completely ignores an object if its not in the schema', () => { + const schema = z.object({ + a: z.string(), + b: z.number(), + }); + + const source = { + c: 1, + d: [1, 2, 3], + }; + + const target = { + a: 'default', + b: 42, + }; + + const result = smoothMerge({ schema, source, target }); + assert.deepEqual(result, { + a: 'default', + b: 42, + }); + }); +}); diff --git a/tgui/packages/common/type-safety.ts b/tgui/packages/common/type-safety.ts new file mode 100644 index 00000000000..71e1c6aa568 --- /dev/null +++ b/tgui/packages/common/type-safety.ts @@ -0,0 +1,56 @@ +import type { ZodObject } from 'zod'; + +type MergeInput = { + /** + * A zod object. + * @see Writing a Zod Schema: https://zod.dev/basics + */ + schema: ZodObject; + /** The input getting merged */ + source: Record; + /** The defaults, which is the shape of the output */ + target: TObj; +}; + +/** + * Merges two objects together while validating the output against a zod schema. + * Different than just parsing - it does not throw errors, it simply discards + * invalid fields and invalid value types. + * + * @example + * + * ```ts + * const schema = z.object({ + * a: z.string(), + * b: z.number(), + * }); + * + * const source = { a: 'hello', b: 'not a number', c: true }; + * const target = { a: 'default', b: 42 }; + * + * const result = smoothMerge({ schema, source, target }); + * // result is { a: 'hello', b: 42 } + * ``` + */ +export function smoothMerge>( + input: MergeInput, +): TObj { + if (Object.keys(input.source).length === 0) return input.target; + + const validated = {}; + + for (const [key, value] of Object.entries(input.source)) { + // Skip keys that are not in the schema + if (!(key in input.schema.shape)) continue; + + const fieldSchema = input.schema.shape[key]; + const result = fieldSchema.safeParse(value); + + // Only assign fields which pass validation + if (result.success) { + validated[key] = result.data; + } + } + + return { ...input.target, ...validated }; +} diff --git a/tgui/packages/tgfont/.gitignore b/tgui/packages/tgfont/.gitignore new file mode 100644 index 00000000000..9b1c8b133c9 --- /dev/null +++ b/tgui/packages/tgfont/.gitignore @@ -0,0 +1 @@ +/dist diff --git a/tgui/packages/tgfont/README_ICON_TUTORIAL.md b/tgui/packages/tgfont/README_ICON_TUTORIAL.md new file mode 100644 index 00000000000..70b52e5a183 --- /dev/null +++ b/tgui/packages/tgfont/README_ICON_TUTORIAL.md @@ -0,0 +1,13 @@ +The following is the process to implement your own icon using an svg. + +If you plan on making your own SVG, consider [Inkscape](https://inkscape.org/). It is free and pretty powerful for vector graphics. + +1. Get whatever SVG you plan on using and put it in the `tgstation\tgui\packages\tgfont\icons` folder. + +2. In VS Code, press Ctrl+Shift+B, and select "tgui: rebuild tgfont". Wait for it to comlpete. + +Now your SVG will be able to be used in the game. + +When you reference your icon that you prefix it with "tg-", otherwise it will not find it. For example, with an SVG named "prosthetic-leg.svg", you would reference it with `icon_state = "tg-prosthetic-leg"`. + +Keep your SVG as simple as possible, the engine has trouble rendering SVGs that have a lot of little disconnected parts. diff --git a/tgui/packages/tgfont/icons/ATTRIBUTIONS.md b/tgui/packages/tgfont/icons/ATTRIBUTIONS.md new file mode 100644 index 00000000000..0491b90e726 --- /dev/null +++ b/tgui/packages/tgfont/icons/ATTRIBUTIONS.md @@ -0,0 +1,8 @@ +bad-touch.svg contains: + +- hug by Phạm Thanh Lộc from the Noun Project +- Fight by Rudez Studio from the Noun Project + +prosthetic-leg.svg contains: + +- prosthetic leg by Gan Khoon Lay from the Noun Project diff --git a/tgui/packages/tgfont/icons/air-tank-slash.svg b/tgui/packages/tgfont/icons/air-tank-slash.svg new file mode 100644 index 00000000000..8c33265f334 --- /dev/null +++ b/tgui/packages/tgfont/icons/air-tank-slash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/air-tank.svg b/tgui/packages/tgfont/icons/air-tank.svg new file mode 100644 index 00000000000..b55f4e7b3aa --- /dev/null +++ b/tgui/packages/tgfont/icons/air-tank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/bad-touch.svg b/tgui/packages/tgfont/icons/bad-touch.svg new file mode 100644 index 00000000000..dba8df87497 --- /dev/null +++ b/tgui/packages/tgfont/icons/bad-touch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/image-minus.svg b/tgui/packages/tgfont/icons/image-minus.svg new file mode 100644 index 00000000000..6fb74bd54fb --- /dev/null +++ b/tgui/packages/tgfont/icons/image-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/image-plus.svg b/tgui/packages/tgfont/icons/image-plus.svg new file mode 100644 index 00000000000..e8b9bec62e7 --- /dev/null +++ b/tgui/packages/tgfont/icons/image-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/nanotrasen-logo.svg b/tgui/packages/tgfont/icons/nanotrasen-logo.svg new file mode 100644 index 00000000000..7cdc98573f4 --- /dev/null +++ b/tgui/packages/tgfont/icons/nanotrasen-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/non-binary.svg b/tgui/packages/tgfont/icons/non-binary.svg new file mode 100644 index 00000000000..c2178ec1b36 --- /dev/null +++ b/tgui/packages/tgfont/icons/non-binary.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/prosthetic-full.svg b/tgui/packages/tgfont/icons/prosthetic-full.svg new file mode 100644 index 00000000000..f9054947044 --- /dev/null +++ b/tgui/packages/tgfont/icons/prosthetic-full.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/prosthetic-leg.svg b/tgui/packages/tgfont/icons/prosthetic-leg.svg new file mode 100644 index 00000000000..9db9fb5cde4 --- /dev/null +++ b/tgui/packages/tgfont/icons/prosthetic-leg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/sound-minus.svg b/tgui/packages/tgfont/icons/sound-minus.svg new file mode 100644 index 00000000000..1da5d4fa5b0 --- /dev/null +++ b/tgui/packages/tgfont/icons/sound-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/sound-plus.svg b/tgui/packages/tgfont/icons/sound-plus.svg new file mode 100644 index 00000000000..33be2c9176f --- /dev/null +++ b/tgui/packages/tgfont/icons/sound-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/icons/syndicate-logo.svg b/tgui/packages/tgfont/icons/syndicate-logo.svg new file mode 100644 index 00000000000..8086d3319a1 --- /dev/null +++ b/tgui/packages/tgfont/icons/syndicate-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tgui/packages/tgfont/package.json b/tgui/packages/tgfont/package.json new file mode 100644 index 00000000000..e98f7aa5b43 --- /dev/null +++ b/tgui/packages/tgfont/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "name": "tgfont", + "type": "module", + "version": "2.0.0", + "scripts": { + "tgfont:build": "svgo icons && node svgtofont.mjs" + }, + "dependencies": { + "svgo": "^3.3.2", + "svgtofont": "^6.3.2" + } +} diff --git a/tgui/packages/tgfont/static/tgfont.css b/tgui/packages/tgfont/static/tgfont.css new file mode 100644 index 00000000000..7b340f899b3 --- /dev/null +++ b/tgui/packages/tgfont/static/tgfont.css @@ -0,0 +1,65 @@ +@font-face { + font-family: "tgfont"; + src: url("tgfont.woff2?t=1747971548188") format("woff2"); +} + +[class^="tg-"], +[class*=" tg-"] { + /* biome-ignore lint/complexity/noImportantStyles: Just leave it */ + font-family: "tgfont" !important; + font-size: inherit; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +:root { + --tg-air-tank-slash: "\ea01"; + --tg-air-tank: "\ea02"; + --tg-bad-touch: "\ea03"; + --tg-image-minus: "\ea04"; + --tg-image-plus: "\ea05"; + --tg-nanotrasen-logo: "\ea06"; + --tg-non-binary: "\ea07"; + --tg-prosthetic-full: "\ea08"; + --tg-prosthetic-leg: "\ea09"; + --tg-sound-minus: "\ea0a"; + --tg-sound-plus: "\ea0b"; + --tg-syndicate-logo: "\ea0c"; +} +.tg-air-tank-slash::before { + content: var(--tg-air-tank-slash); +} +.tg-air-tank::before { + content: var(--tg-air-tank); +} +.tg-bad-touch::before { + content: var(--tg-bad-touch); +} +.tg-image-minus::before { + content: var(--tg-image-minus); +} +.tg-image-plus::before { + content: var(--tg-image-plus); +} +.tg-nanotrasen-logo::before { + content: var(--tg-nanotrasen-logo); +} +.tg-non-binary::before { + content: var(--tg-non-binary); +} +.tg-prosthetic-full::before { + content: var(--tg-prosthetic-full); +} +.tg-prosthetic-leg::before { + content: var(--tg-prosthetic-leg); +} +.tg-sound-minus::before { + content: var(--tg-sound-minus); +} +.tg-sound-plus::before { + content: var(--tg-sound-plus); +} +.tg-syndicate-logo::before { + content: var(--tg-syndicate-logo); +} diff --git a/tgui/packages/tgfont/static/tgfont.woff2 b/tgui/packages/tgfont/static/tgfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..2586080a0d9b8da3491d4c1e47d2d89ec441f7e5 GIT binary patch literal 2472 zcmV;Z30L-aPew8T0RR91012o73jhEB01`w100~$C0RR9100000000000000000000 z0000SR0d!GgbE6lB$03dHUcCAGz%O61Rw>2eg}bA8!-=2lqXgq`)a^;)H7nzLdBDr znRhT26%{%ODxMja%U}5zjKQSd=2E8t;HgB$u{4$^pi!|UTdDl=N$(_GdwXy1Fyrlo z2Y%gu=jzRTxEalzW=O(TIj`Hs4Gq%pw9S8~%^62qfdzJB^yiAaTY_49zFO7C8BB{q~Cg}U3`FOvo>1_rE5 z-Qxi6xC!JANE2nVV-(QlEAC7z1Gis6FHH0)hk0{v$PQw82^c^D@e}il-ty#jln?PP zan4KDq)M!5^2+t^|5w5mr!7!fqR^P%KY125PB`O&D+mYBh${om#C)%WiE*g}165$4 z8VuBcfjYoIEih0U4Acn>)ENxa1q{>`d189EZG3?QP}=}~0yKNROtx?wE-{BJ95qP2 zh3(2PIg6OunFb@qEK^f~mEi=#EO!%Qroc4MhJy$=rN;VtazDA{=!jaX5gyQJ zW2Q+e+7D`J?N?7t9Ki8o!6UOhNTuu`)u2?XBlihLb{ttF>W$%#ibwg1;SOFbZz?eb zZG7-)%Ht;w_V*n)actk(b=7DVPT(kvVJPY?SccaUMR+COB{9e)`IV+pM=nUu9h!ak zyzJspQiIFo3I%K`8>LhX6X`jd>}+&k{kq+5#PC6DLZMi}#j?A`PVcqO?Okn!6ErqB zx<)n4L^=XkKHKEIAc#`609OUeJj#_t(gTpLnRFkpm-oX=*+Iy#PImtA>_g|I7miRz zFHSZi2*n^5t5nD=_cX@8hrv){ckYV7QcyQ;aHqn=j5FE#)hh-)GHq!KjR4&%AL>x` zZQYyGND1_ea^0p~pAA)zerrL`9tI=gHh@+0eJ;3n%~VRGVd%)T+M?BR1KBTut@#b5 z;rMKthIOTC^)z$0OX}J5Wm=}as--knG?JN^^^`do_1%nVE%`3_uKCvAeoBs9FmTC2 z&5+_lt~@z!N8mR1eZFcnMu+WATmhSs-Me8Kf2YXNREE^?AIZUF*kO;K3jogJgu3C@G$X znn?F8DAN>Eo?OqFr~@aa9BQw3Xt=2=_zhvG8Z1!53`T?H{tGo4oB>9tX*D-QMG7=o zdxR?eJXSprkHOG}@D<$MGzNEbmX8?wSjAm2$d~hYT$zHu+;zxG&Ubm5 zDy(2gqrot4?Nx^~C^n?(CAz!ZG0#*oPp1MliHhqL+oXt$UKfipeSSe4OStYF3@d4u z0?UUdF)iaiu?NB6>Yob;j%1jeiz*IM@zNH_A(_@JBSWVK${Mq7w6@@(K+*@0+!Q+Z z36n&9$$g?EVc(?rTfk~>^`ga#YHE1=E~~EU8f6Ro?&(1=Boiq|JcR2oRH4IB`6O1n zv>V{e`H#zAu}7G|cri!VjqF{_{qL_-rJ4Lnqp8;8Uv8|MKD&FuL;t_Fr_E6_x5a&( zk%I;N2{?s_&D}uS+1YxD5j?xcfoDa1?!!XCF`$k6oqW8qvb=prpDZu0ve$_7I+1f@ ziCffQEry>Be3Yv7@y^Qf`q#YWd?4gzhUWywHxA=TLwkdkjq8r%KZkaQiV(u;W{qc? z?i-mNw8N%kPqCpbSuyh_dl7p)OUwhD#}9dl($hV249;+Z7um7ID>I(V0y z6T3JgkvaMEb@Fhe4GEo9O=OdRf;@y|O>!q+gYfjhw{O|jnANtN% z8$j(nJIWc#0@a`X9eA;MmU#u@@eD>%b4N1GD}pu;clL3C@7L%VhsOJ*c_&sUrc1g@ z=LRkenm0Z?S6uUN{oLXyqRd?GxR$Rke6}>~63m^DMipY@%rzy8!#cc=<3(R&(C&Tq zk$YSpi|uACt~B9h6@0q4yKmW{xa{CT-E{KZb3z+R&WxPsThdbEptrf~s6nW&cPg)! zxgoWY>+!L3yvX!>TI$kUxY0g74n7KY8n|Zcml(D(yJw)J^>@4j5(5cyk!6!O`n<$2 z8?^mE%QN-*q}%v!aGBFD2l!+z%jf|8jK4sAh)*-O^mdc0cJ)2(+e?x6@m^)2dE{ps zz9X0Mq+)fR5ZcRXiG5ENYfE)pE|Vpe|G&GsP0RNupBXe0IbQ#5nF09Po0mxdodi&C z|1#SF_|%@tY~0v-5+Do%&U!lhm#LmS6dj%ngj!(5q&HB$-3_FTJ~2irRmL!M`vx(| zK6^VKx;$h_>m6xogpZgE4G^+<#&^hJ{D{dj;1dcM|6(dU{vV^tmSADPB;YL#5<%3r zWH0wfmF5yw9Meu*Q27u6Ghc@!?bMaxSk)47Oo5= z@M>s5bXbZWw>%}jfim&JDvwA&jfg{{D<2n*MWUNPK%yd=f+1ueD = {}): Promise { + const query = Object.keys(params) + .map( + (key) => + `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`, + ) + .join('&'); + logger.log( + `topic call at ${this.client.defaults.baseURL}/dummy.htm?${query}`, + ); + return this.client.get(`/dummy.htm?${query}`); + } + + static async getInstancesByPids(pids: number[]): Promise { + const instances: DreamSeeker[] = []; + const pidsToResolve: number[] = []; + + for (const pid of pids) { + const instance = instanceByPid.get(pid); + if (instance) { + instances.push(instance); + } else { + pidsToResolve.push(pid); + } + } + + if (pidsToResolve.length === 0) { + return instances; + } + + const command = 'netstat -ano | findstr TCP | findstr 0.0.0.0:0'; + + try { + const { stdout } = await promisify(exec)(command, { + // Max buffer of 1MB (default is 200KB) + maxBuffer: 1024 * 1024, + }); + + // Line format: + // proto addr mask mode pid + const entries: Entry[] = []; + const lines = stdout.split('\r\n'); + + for (const line of lines) { + const words = line.match(/\S+/g); + if (!words || words.length === 0) { + continue; + } + const entry: Entry = { + addr: words[1], + pid: parseInt(words[4], 10), + }; + if (pidsToResolve.includes(entry.pid)) { + entries.push(entry); + } + } + + const len = entries.length; + logger.log('found', len, plural('instance', len)); + for (const entry of entries) { + const { pid, addr } = entry; + const instance = new DreamSeeker(pid, addr); + instances.push(instance); + instanceByPid.set(pid, instance); + } + } catch (err) { + if (err.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') { + logger.error(err.message, err.code); + } else { + logger.error(err); + } + return []; + } + return instances; + } +} + +function plural(word: string, n: number): string { + return n !== 1 ? `${word}s` : word; +} diff --git a/tgui/packages/tgui-dev-server/index.ts b/tgui/packages/tgui-dev-server/index.ts new file mode 100644 index 00000000000..f7fe55851e4 --- /dev/null +++ b/tgui/packages/tgui-dev-server/index.ts @@ -0,0 +1,31 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import fs from 'node:fs'; + +import { reloadByondCache } from './reloader'; +import { RspackCompiler } from './webpack'; + +const reloadOnce = process.argv.includes('--reload'); + +async function setupServer() { + fs.mkdirSync('./public/.tmp', { recursive: true }); + + const compiler = new RspackCompiler(); + + await compiler.setup(); + + // Reload cache once + if (reloadOnce) { + await reloadByondCache(compiler.bundleDir); + return; + } + + // Run a development server + await compiler.watch(); +} + +setupServer(); diff --git a/tgui/packages/tgui-dev-server/link/client.ts b/tgui/packages/tgui-dev-server/link/client.ts new file mode 100644 index 00000000000..eb8d542a687 --- /dev/null +++ b/tgui/packages/tgui-dev-server/link/client.ts @@ -0,0 +1,172 @@ +type Messenger = (msg: any) => void; + +let socket: WebSocket | undefined; +const queue: string[] = []; +const subscribers: Messenger[] = []; + +function ensureConnection() { + if (socket) return; + console.log('Creating a connection'); + + socket = new WebSocket('ws://127.0.0.1:3000'); + + socket.onopen = () => { + // Empty the message queue + while (queue.length !== 0) { + const msg = queue.shift(); + if (msg) { + socket?.send(msg); + } + } + }; + + socket.onmessage = (event) => { + const msg = JSON.parse(event.data); + for (const subscriber of subscribers) { + subscriber(msg); + } + }; + + socket.onerror = (err) => { + console.log('WebSocket error:', err); + }; + + window.addEventListener('unload', () => socket?.close()); +} + +function primitiveReviver(value: unknown): any { + if (typeof value === 'number' && !Number.isFinite(value)) { + return { + __number__: String(value), + }; + } + if (typeof value === 'undefined') { + return { + __undefined__: true, + }; + } + return value; +} + +export function sendLogEntry( + level: number, + ns: string | null = 'client', + ...args: any[] +): void { + if (process.env.NODE_ENV === 'development') { + try { + sendMessage({ + type: 'log', + payload: { + level, + ns, + args, + }, + }); + } catch (err) {} + } +} + +export function sendMessage(msg: Record): void { + if (process.env.NODE_ENV === 'development' && socket) { + const json = serializeObject(msg); + // Send message using WebSocket + if (!window.WebSocket) return; + + ensureConnection(); + if (socket.readyState === WebSocket.OPEN) { + socket.send(json); + } else { + // Keep only 100 latest messages in the queue + if (queue.length > 100) { + queue.shift(); + } + queue.push(json); + } + } +} + +/** A json serializer which handles circular references and other junk. */ +function serializeObject(obj: Record): string { + let refs: string[] = []; + + function objectReviver(key: string, value: any) { + if (typeof value !== 'object') { + return primitiveReviver(value); + } + + if (value === null) { + return value; + } + // Circular reference + if (refs.includes(value)) { + return '[circular ref]'; + } + refs.push(value); + // Error object + const isError = + value instanceof Error || + (value.code && value.message && value.message.includes('Error')); + if (isError) { + return { + __error__: true, + string: String(value), + stack: value.stack, + }; + } + // Array + if (Array.isArray(value)) { + return value.map(primitiveReviver); + } + return value; + } + + const json = JSON.stringify(obj, objectReviver); + refs = []; + return json; +} + +export function setupHotReloading(): void { + if (process.env.NODE_ENV === 'development' && window.WebSocket) { + console.log('Setting up hot reloading...'); + if (socket) { + socket.close(); + socket = undefined; + subscribers.length = 0; + } + ensureConnection(); + subscribe(({ type }) => { + if (type !== 'hotUpdate') return; + + const status = import.meta.webpackHot?.status(); + if (status === 'ready') { + import.meta.webpackHot + ?.apply({ + ignoreUnaccepted: true, + ignoreDeclined: true, + ignoreErrored: true, + }) + .then((modules) => { + console.log('outdated modules:', modules); + }) + .catch((err) => { + console.log(import.meta.webpackHot?.status()); + console.error('Hot reload error:', err); + }); + } else if (status === 'idle') { + import.meta.webpackHot + ?.check(true) + .then((updatedModules) => { + console.log('Updated modules:', updatedModules); + }) + .catch((err) => { + console.error('Hot reload error:', err); + }); + } + }); + } +} + +export function subscribe(fn: Messenger): void { + subscribers.push(fn); +} diff --git a/tgui/packages/tgui-dev-server/link/retrace.ts b/tgui/packages/tgui-dev-server/link/retrace.ts new file mode 100644 index 00000000000..6fd1bc27ab0 --- /dev/null +++ b/tgui/packages/tgui-dev-server/link/retrace.ts @@ -0,0 +1,88 @@ +import path from 'node:path'; + +import { SourceMapConsumer } from 'source-map'; +import { parse as parseStackTrace } from 'stacktrace-parser'; + +import { createLogger } from '../logging'; +import { resolveGlob } from '../util'; + +type SourceMap = { + file: string; + consumer: SourceMapConsumer; +}; + +const logger = createLogger('retrace'); + +const sourceMaps: SourceMap[] = []; + +export async function loadSourceMaps(bundleDir: string): Promise { + // Destroy and garbage collect consumers + while (sourceMaps.length !== 0) { + const map = sourceMaps.shift(); + if (!map?.consumer) continue; + map.consumer.destroy(); + } + + // Load new sourcemaps + const files = await resolveGlob(bundleDir, '*.map'); + for (const file of files) { + try { + const loc = path.resolve(bundleDir, file); + const parsed = await Bun.file(loc).json(); + const consumer = await new SourceMapConsumer(parsed); + + sourceMaps.push({ file, consumer }); + } catch (err) { + logger.error(err); + } + } + + logger.log(`loaded ${sourceMaps.length} source maps`); +} + +export function retrace(stack: string): string | undefined { + if (typeof stack !== 'string') { + logger.log('ERROR: Stack is not a string!', stack); + return stack; + } + const header = stack.split(/\n\s.*at/)[0]; + const mappedStack = parseStackTrace(stack) + .map((frame) => { + if (!frame.file) { + return frame; + } + // Find the correct source map + const sourceMap = sourceMaps.find((sourceMap) => { + return frame.file!.includes(sourceMap.file); + }); + if (!sourceMap) { + return frame; + } + // Map the frame + const { consumer } = sourceMap; + const mappedFrame = consumer.originalPositionFor({ + line: frame.lineNumber || 0, + column: frame.column || 0, + }); + return { + ...frame, + file: mappedFrame.source, + lineNumber: mappedFrame.line, + column: mappedFrame.column, + }; + }) + .map((frame) => { + // Stringify the frame + const { file, methodName, lineNumber } = frame; + if (!file) { + return ` at ${methodName}`; + } + const compactPath = file + .replace(/^rspack:\/\/\/?/, './') + .replace(/.*node_modules\//, ''); + return ` at ${methodName} (${compactPath}:${lineNumber})`; + }) + .join('\n'); + + return `${header}\n${mappedStack}`; +} diff --git a/tgui/packages/tgui-dev-server/link/server.ts b/tgui/packages/tgui-dev-server/link/server.ts new file mode 100644 index 00000000000..9b2ef1e4c85 --- /dev/null +++ b/tgui/packages/tgui-dev-server/link/server.ts @@ -0,0 +1,116 @@ +import { inspect } from 'node:util'; + +import type { ServerWebSocket } from 'bun'; + +import { createLogger, directLog } from '../logging'; +import { retrace } from './retrace'; + +let server: Bun.Server; +const logger = createLogger('link'); +const DEBUG = process.argv.includes('--debug'); + +export function setupLink() { + server = Bun.serve({ + fetch: upgradeServer, + development: true, + hostname: '127.0.0.1', + port: 3000, + websocket: { + open(ws) { + ws.subscribe('link'); + logger.log('client connected'); + }, + close(ws) { + ws.unsubscribe('link'); + logger.log('client disconnected'); + }, + message: handleLinkMessage, + }, + }); +} + +export function broadcastMessage(msg: Record): void { + const subscribers = server.subscriberCount('link'); + if (subscribers === 0) return; + + server?.publish('link', JSON.stringify(msg)); +} + +function deserializeObject(str: any): any { + return JSON.parse(str, (_key: string, value: any) => { + if (typeof value === 'object' && value !== null) { + if (value.__undefined__) { + // NOTE: You should not rely on deserialized object's undefined, + // this is purely for inspection purposes. + return { + [inspect.custom]: () => undefined, + }; + } + if (value.__number__) { + return parseFloat(value.__number__); + } + if (value.__error__) { + if (!value.stack) { + return value.string; + } + return retrace(value.stack); + } + return value; + } + return value; + }); +} + +function handleLinkMessage( + _ws: ServerWebSocket, + message: string | Buffer, +): void { + const deserializedMsg = deserializeObject(message); + const { type, payload } = deserializedMsg; + + if (type === 'log') { + const { level, ns, args } = payload; + // Skip debug messages + if (level <= 0 && !DEBUG) return; + + directLog( + ns, + ...args.map((arg) => { + if (typeof arg === 'object') { + return inspect(arg, { + depth: Infinity, + colors: true, + compact: 8, + }); + } + return arg; + }), + ); + + return; + } + if (type === 'relay') { + broadcastMessage(payload); + + return; + } + + logger.log('unhandled message', JSON.stringify(message)); +} + +function upgradeServer(req: Request, srv: Bun.Server) { + const client = crypto.randomUUID(); + + const upgraded = srv.upgrade(req, { + data: { + id: client, + createdAt: Date.now(), + }, + }); + + if (upgraded) { + return new Response('Ok'); + } else { + return new Response('Upgrade failed', { status: 500 }); + } +} diff --git a/tgui/packages/tgui-dev-server/logging.ts b/tgui/packages/tgui-dev-server/logging.ts new file mode 100644 index 00000000000..bf46b365ce3 --- /dev/null +++ b/tgui/packages/tgui-dev-server/logging.ts @@ -0,0 +1,72 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +type Fn = (...args: any[]) => void; + +const inception = Date.now(); + +// Runtime detection. Yes, even in bun! +const isNode = process?.release?.name === 'node'; +let isChrome = false; +try { + isChrome = window.navigator.userAgent.toLowerCase().includes('chrome'); +} catch {} + +// Timestamping function +function getTimestamp(): string { + const timestamp = String(Date.now() - inception) + .padStart(4, '0') + .padStart(7, ' '); + const seconds = timestamp.slice(0, timestamp.length - 3); + const millis = timestamp.slice(-3); + + return `${seconds}.${millis}`; +} + +const getPrefix = (() => { + if (isNode) { + // Escape sequences + const ESC = { + dimmed: '\x1b[38;5;240m', + bright: '\x1b[37;1m', + reset: '\x1b[0m', + }; + return (ns: string) => [ + `${ESC.dimmed}${getTimestamp()} ${ESC.bright}${ns}${ESC.reset}`, + ]; + } + if (isChrome) { + // Styles + const styles = { + dimmed: 'color: #888', + bright: 'font-weight: bold', + }; + return (ns: string) => [ + `%c${getTimestamp()}%c ${ns}`, + styles.dimmed, + styles.bright, + ]; + } + + return (ns: string) => [`${getTimestamp()} ${ns}`]; +})(); + +/** Creates a logger object. */ +export function createLogger(ns: string): Record { + return { + log: (...args) => console.log(...getPrefix(ns), ...args), + trace: (...args) => console.trace(...getPrefix(ns), ...args), + debug: (...args) => console.debug(...getPrefix(ns), ...args), + info: (...args) => console.info(...getPrefix(ns), ...args), + warn: (...args) => console.warn(...getPrefix(ns), ...args), + error: (...args) => console.error(...getPrefix(ns), ...args), + }; +} + +/** Explicitly log with chosen namespace. */ +export function directLog(ns: string, ...args: any[]): void { + console.log(...getPrefix(ns), ...args); +} diff --git a/tgui/packages/tgui-dev-server/package.json b/tgui/packages/tgui-dev-server/package.json new file mode 100644 index 00000000000..3ea255feadb --- /dev/null +++ b/tgui/packages/tgui-dev-server/package.json @@ -0,0 +1,11 @@ +{ + "name": "tgui-dev-server", + "version": "6.0.0", + "dependencies": { + "axios": "^1.10.0", + "source-map": "^0.7.4", + "stacktrace-parser": "^0.1.11" + }, + "private": true, + "type": "module" +} diff --git a/tgui/packages/tgui-dev-server/reloader.ts b/tgui/packages/tgui-dev-server/reloader.ts new file mode 100644 index 00000000000..fdbb2aa066c --- /dev/null +++ b/tgui/packages/tgui-dev-server/reloader.ts @@ -0,0 +1,133 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import os from 'node:os'; +import path from 'node:path'; + +import { DreamSeeker } from './dreamseeker'; +import { createLogger } from './logging'; +import { resolveGlob, resolvePath } from './util'; +import { regQuery } from './winreg'; + +const logger = createLogger('reloader'); + +// Basic glob pattern for bundle files +const bundleGlob = '*.{bundle,chunk,hot-update}.*'; + +const HOME = os.homedir(); +const SEARCH_LOCATIONS = [ + // Custom location + process.env.BYOND_CACHE, + // Windows + `${HOME}/*/BYOND/cache`, + // Wine + `${HOME}/.wine/drive_c/users/*/*/BYOND/cache`, + // Lutris + `${HOME}/Games/byond/drive_c/users/*/*/BYOND/cache`, + // WSL + `/mnt/c/Users/*/*/BYOND/cache`, +]; + +let cacheRoot: string; + +export async function findCacheRoot(): Promise { + if (cacheRoot) { + return cacheRoot; + } + logger.log('looking for byond cache'); + // Find BYOND cache folders + + for (const pattern of SEARCH_LOCATIONS) { + if (!pattern) { + continue; + } + + const paths = await resolveGlob(pattern); + if (paths.length > 0) { + cacheRoot = paths[0]; + onCacheRootFound(cacheRoot); + return cacheRoot; + } + } + + // Query the Windows Registry + if (process.platform === 'win32') { + logger.log('querying windows registry'); + const userpath = await regQuery( + 'HKCU\\Software\\Dantom\\BYOND', + 'userpath', + ); + if (userpath) { + cacheRoot = `${userpath.replace(/\\$/, '').replace(/\\/g, '/')}/cache`; + await onCacheRootFound(cacheRoot); + return cacheRoot; + } + } + logger.log('found no cache directories'); +} + +async function onCacheRootFound(cacheRoot: string): Promise { + logger.log(`found cache at '${cacheRoot}'`); + // Plant a dummy browser window file, we'll be using this to avoid world topic. For byond 514. + await Bun.write(`${cacheRoot}/dummy.htm`, ''); +} + +export async function reloadByondCache(bundleDir: string): Promise { + const cacheRoot = await findCacheRoot(); + if (!cacheRoot) return; + + // Find tmp folders in cache + const cacheDirs = await resolveGlob(cacheRoot, 'tmp*'); + if (cacheDirs.length === 0) { + logger.log('found no tmp folder in cache'); + return; + } + + const pids = cacheDirs.map((cacheDir) => { + return parseInt(cacheDir.split('\\cache\\tmp')[1], 10); + }); + + const dssPromise = DreamSeeker.getInstancesByPids(pids); + // Copy assets + const assets = await resolveGlob(bundleDir, bundleGlob); + + for (const cacheDir of cacheDirs) { + // Clear garbage + const garbage = await resolveGlob(cacheDir, bundleGlob); + for (const file of garbage) { + await Bun.file(file).delete(); + } + + try { + // Plant a dummy browser window file, we'll be using this to avoid world topic. For byond 515-516. + await Bun.write(`${cacheDir}/dummy.htm`, ''); + + // Copy assets + for (const asset of assets) { + const destination = resolvePath(cacheDir, path.basename(asset)); + const input = Bun.file(asset); + const output = Bun.file(destination); + + await Bun.write(output, input); + } + logger.log(`copied ${assets.length} files to '${cacheDir}'`); + } catch (err) { + logger.error(`failed copying to '${cacheDir}'`); + logger.error(err); + } + } + // Notify dreamseeker + const dss = await dssPromise; + if (dss.length > 0) { + logger.log(`notifying dreamseeker`); + for (const dreamseeker of dss) { + dreamseeker.topic({ + tgui: 1, + type: 'cacheReloaded', + }); + } + } +} diff --git a/tgui/packages/tgui-dev-server/require.ts b/tgui/packages/tgui-dev-server/require.ts new file mode 100644 index 00000000000..d1f5ec4ce16 --- /dev/null +++ b/tgui/packages/tgui-dev-server/require.ts @@ -0,0 +1,9 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { createRequire } from 'node:module'; + +export const require = createRequire(import.meta.url); diff --git a/tgui/packages/tgui-dev-server/util.ts b/tgui/packages/tgui-dev-server/util.ts new file mode 100644 index 00000000000..3c162b4abab --- /dev/null +++ b/tgui/packages/tgui-dev-server/util.ts @@ -0,0 +1,40 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import path from 'node:path'; + +import { Glob } from 'bun'; + +export const resolvePath = path.resolve; + +/** Combines path.resolve with glob patterns. */ +export async function resolveGlob( + directory: string, + pattern = '*', +): Promise { + // If no pattern is supplied, just return the directory if it exists + if (pattern === '*') { + try { + const stat = await Bun.file(directory).stat(); + if (stat?.isDirectory()) { + return [directory]; + } + } catch (e) { + return []; + } + return []; + } + + // Otherwise, use glob logic + const glob = new Glob(pattern); + const results: string[] = []; + + for await (const match of glob.scan({ onlyFiles: false, cwd: directory })) { + results.push(path.resolve(directory, match)); + } + + return results; +} diff --git a/tgui/packages/tgui-dev-server/webpack.ts b/tgui/packages/tgui-dev-server/webpack.ts new file mode 100644 index 00000000000..3b1eb522dea --- /dev/null +++ b/tgui/packages/tgui-dev-server/webpack.ts @@ -0,0 +1,69 @@ +import { createRequire } from 'node:module'; + +import { config } from '../../rspack.config-dev'; +import { loadSourceMaps } from './link/retrace'; +import { broadcastMessage, setupLink } from './link/server'; +import { createLogger } from './logging'; +import { reloadByondCache } from './reloader'; +import { resolveGlob } from './util'; + +const logger = createLogger('rspack'); + +export class RspackCompiler { + rspack: any; + config: any; + bundleDir: string; + + async setup() { + // Create a require context that is relative to project root + // and retrieve all necessary dependencies. + const requireFromRoot = createRequire(`${import.meta.dirname}/../../..`); + const rspack = await requireFromRoot('@rspack/core'); + + this.rspack = rspack; + this.config = config; + this.bundleDir = config.output?.path || ''; + } + + async watch() { + logger.log('setting up'); + setupLink(); + // Instantiate the compiler + const compiler = this.rspack.rspack(this.config); + + // Clear garbage before compiling + compiler.hooks.watchRun.tapPromise('tgui-dev-server', async () => { + const files = await resolveGlob(this.bundleDir, '*.hot-update.*'); + for (const file of files) { + await Bun.file(file).delete(); + } + logger.log('compiling'); + }); + + // Start reloading when it's finished + compiler.hooks.done.tap('tgui-dev-server', async () => { + // Load source maps + await loadSourceMaps(this.bundleDir); + // Reload cache + await reloadByondCache(this.bundleDir); + // Notify all clients that update has happened + broadcastMessage({ + type: 'hotUpdate', + }); + }); + // Start watching + logger.log('watching for changes'); + compiler.watch({}, (err, stats) => { + if (err) { + logger.error('compilation error', err); + return; + } + stats + ?.toString(this.config.stats) + .split('\n') + .forEach((line) => { + logger.log(line); + }); + }); + } +} diff --git a/tgui/packages/tgui-dev-server/winreg.ts b/tgui/packages/tgui-dev-server/winreg.ts new file mode 100644 index 00000000000..c3c0a85a0bf --- /dev/null +++ b/tgui/packages/tgui-dev-server/winreg.ts @@ -0,0 +1,52 @@ +/** + * Tools for dealing with Windows Registry bullshit. + * + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { exec } from 'node:child_process'; +import { promisify } from 'node:util'; + +import { createLogger } from './logging'; + +const logger = createLogger('winreg'); + +/** Query a registry key. */ +export async function regQuery( + path: string, + key: string, +): Promise { + if (process.platform !== 'win32') { + return; + } + try { + const command = `reg query "${path}" /v ${key}`; + const { stdout } = await promisify(exec)(command); + const keyPattern = ` ${key} `; + const indexOfKey = stdout.indexOf(keyPattern); + + if (indexOfKey === -1) { + logger.error('could not find the registry key'); + return; + } + + const indexOfEol = stdout.indexOf('\r\n', indexOfKey); + if (indexOfEol === -1) { + logger.error('could not find the end of the line'); + return; + } + + const indexOfValue = stdout.indexOf(' ', indexOfKey + keyPattern.length); + if (indexOfValue === -1) { + logger.error('could not find the start of the key value'); + return; + } + + return stdout.substring(indexOfValue + 4, indexOfEol); + } catch (err) { + logger.error(err); + return; + } +} diff --git a/tgui/packages/tgui-panel/Notifications.tsx b/tgui/packages/tgui-panel/Notifications.tsx new file mode 100644 index 00000000000..9c87ca633a7 --- /dev/null +++ b/tgui/packages/tgui-panel/Notifications.tsx @@ -0,0 +1,30 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { Flex } from 'tgui-core/components'; + +export function Notifications(props) { + const { children } = props; + + return
{children}
; +} + +function NotificationsItem(props) { + const { rightSlot, children } = props; + + return ( + + + {children} + + {rightSlot && ( + {rightSlot} + )} + + ); +} + +Notifications.Item = NotificationsItem; diff --git a/tgui/packages/tgui-panel/Panel.tsx b/tgui/packages/tgui-panel/Panel.tsx new file mode 100644 index 00000000000..7ad6ebed3d0 --- /dev/null +++ b/tgui/packages/tgui-panel/Panel.tsx @@ -0,0 +1,102 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { useAtom, useAtomValue } from 'jotai'; +import { Pane } from 'tgui/layouts'; +import { Button, Section, Stack } from 'tgui-core/components'; +import { visibleAtom } from './audio/atoms'; +import { NowPlayingWidget } from './audio/NowPlayingWidget'; +import { ChatPanel } from './chat/ChatPanel'; +import { ChatTabs } from './chat/ChatTabs'; +import { useChatPersistence } from './chat/use-chat-persistence'; +import { gameAtom } from './game/atoms'; +import { useKeepAlive } from './game/use-keep-alive'; +import { Notifications } from './Notifications'; +import { PingIndicator } from './ping/PingIndicator'; +import { ReconnectButton } from './reconnect'; +import { settingsVisibleAtom } from './settings/atoms'; +import { SettingsPanel } from './settings/SettingsPanel'; +import { useSettings } from './settings/use-settings'; + +export function Panel(props) { + const [audioVisible, setAudioVisible] = useAtom(visibleAtom); + const game = useAtomValue(gameAtom); + const { settings } = useSettings(); + const [settingsVisible, setSettingsVisible] = useAtom(settingsVisibleAtom); + useChatPersistence(); + useKeepAlive(); + + return ( + + + +
+ + + + + + + + +
+
+ {audioVisible && ( + +
+ +
+
+ )} + {settingsVisible && ( + + + + )} + +
+ + + + + {game.connectionLostAt && ( + }> + You are either AFK, experiencing lag or the connection has + closed. + + )} + {game.roundRestartedAt && ( + + The connection has been closed because the server is + restarting. Please wait while you automatically reconnect. + + )} + +
+
+
+
+ ); +} diff --git a/tgui/packages/tgui-panel/app.tsx b/tgui/packages/tgui-panel/app.tsx new file mode 100644 index 00000000000..efe198ae3a7 --- /dev/null +++ b/tgui/packages/tgui-panel/app.tsx @@ -0,0 +1,12 @@ +import { Provider } from 'jotai'; +import { store } from './events/store'; +import { Panel } from './Panel'; + +/** Just an expandable wrapper for setup shenanigans and providers */ +export function App() { + return ( + + + + ); +} diff --git a/tgui/packages/tgui-panel/audio/NowPlayingWidget.tsx b/tgui/packages/tgui-panel/audio/NowPlayingWidget.tsx new file mode 100644 index 00000000000..a89ae1e31c5 --- /dev/null +++ b/tgui/packages/tgui-panel/audio/NowPlayingWidget.tsx @@ -0,0 +1,108 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { useAtomValue } from 'jotai'; +import { Button, Collapsible, Flex, Knob, Section } from 'tgui-core/components'; +import { toFixed } from 'tgui-core/math'; +import { useSettings } from '../settings/use-settings'; +import { metaAtom, playingAtom } from './atoms'; +import { player } from './handlers'; + +export function NowPlayingWidget(props) { + const { settings, updateSettings } = useSettings(); + const meta = useAtomValue(metaAtom); + const { + album = 'Unknown Album', + artist = 'Unknown Artist', + duration, + link, + title, + upload_date = 'Unknown Data', + } = meta || {}; + + const playing = useAtomValue(playingAtom); + + const date = !Number.isNaN(upload_date) + ? upload_date?.substring(0, 4) + + '-' + + upload_date?.substring(4, 6) + + '-' + + upload_date?.substring(6, 8) + : upload_date; + + return ( + + {playing ? ( + + { + +
+ {link !== 'Song Link Hidden' && ( + + URL: {link} + + )} + + Duration: {duration} + + {artist !== 'Song Artist Hidden' && + artist !== 'Unknown Artist' && ( + + Artist: {artist} + + )} + {album !== 'Song Album Hidden' && album !== 'Unknown Album' && ( + + Album: {album} + + )} + {upload_date !== 'Song Upload Date Hidden' && + upload_date !== 'Unknown Date' && ( + + Uploaded: {date} + + )} +
+
+ } +
+ ) : ( + + Nothing to play. + + )} + {playing && ( + + + + )} + + +
+ {MESSAGE_TYPES.filter( + (typeDef) => !typeDef.important && !typeDef.admin, + ).map((typeDef) => ( + toggleAcceptedType(typeDef.type)} + > + {typeDef.name} + + ))} + + {MESSAGE_TYPES.filter( + (typeDef) => !typeDef.important && typeDef.admin, + ).map((typeDef) => ( + toggleAcceptedType(typeDef.type)} + > + {typeDef.name} + + ))} + +
+ + ); +} diff --git a/tgui/packages/tgui-panel/chat/ChatPanel.tsx b/tgui/packages/tgui-panel/chat/ChatPanel.tsx new file mode 100644 index 00000000000..17171ddf81b --- /dev/null +++ b/tgui/packages/tgui-panel/chat/ChatPanel.tsx @@ -0,0 +1,76 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { useAtom, useAtomValue } from 'jotai'; +import { useEffect, useRef } from 'react'; +import { Button } from 'tgui-core/components'; +import { + chatPagesRecordAtom, + currentPageIdAtom, + scrollTrackingAtom, +} from './atom'; +import { chatRenderer } from './renderer'; +import type { Page } from './types'; + +type Props = { + fontSize?: string; + lineHeight: string | number; +}; + +export function ChatPanel(props: Props) { + const ref = useRef(null); + const scrollTracking = useAtomValue(scrollTrackingAtom); + // Page stuff + const currentPageId = useAtomValue(currentPageIdAtom); + const [pagesRecord, setPagesRecord] = useAtom(chatPagesRecordAtom); + + /** Mounts the renderer */ + useEffect(() => { + if (ref.current) { + chatRenderer.mount(ref.current); + } + }, []); + + /** Resets unread count when scroll tracking is enabled */ + useEffect(() => { + if (scrollTracking) { + const draft: Page = { + ...pagesRecord[currentPageId], + unreadCount: 0, + }; + + setPagesRecord({ + ...pagesRecord, + [currentPageId]: draft, + }); + } + }, [scrollTracking]); + + /** Updates the style of the chat panel */ + useEffect(() => { + chatRenderer.assignStyle({ + width: '100%', + 'white-space': 'pre-wrap', + 'font-size': props.fontSize, + 'line-height': props.lineHeight, + }); + }, [props.fontSize, props.lineHeight]); + + return ( + <> +
+ {!scrollTracking && ( + + )} + + ); +} diff --git a/tgui/packages/tgui-panel/chat/ChatTabs.tsx b/tgui/packages/tgui-panel/chat/ChatTabs.tsx new file mode 100644 index 00000000000..7dc238a582a --- /dev/null +++ b/tgui/packages/tgui-panel/chat/ChatTabs.tsx @@ -0,0 +1,61 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { useAtom } from 'jotai'; +import { Box, Button, Stack, Tabs } from 'tgui-core/components'; +import { settingsVisibleAtom } from '../settings/atoms'; +import { useChatPages } from './use-chat-pages'; + +type UnreadCountWidgetProps = { + value: number; +}; + +function UnreadCountWidget(props: UnreadCountWidgetProps) { + const { value } = props; + + return {Math.min(value, 99)}; +} + +export function ChatTabs(props) { + const { addChatPage, changeChatPage, pages, pagesRecord, currentPageId } = + useChatPages(); + + const [, setSettingsVisible] = useAtom(settingsVisibleAtom); + + return ( + + + + {pages.map((page) => { + const actual = pagesRecord[page]; + return ( + changeChatPage(actual)} + > + {actual.name} + {!actual.hideUnreadCount && actual.unreadCount > 0 && ( + + )} + + ); + })} + + + + + + ))} + + + + + + + + + + + + + + {!freeFont ? ( + { + setFreeFont(!freeFont); + }} + > + Custom font + + } + > + {FONTS.map((FONT) => ( + + ))} + + ) : ( + + + updateSettings({ + fontFamily: value, + }) + } + /> + + + )} + + + + + + toFixed(value)} + onChange={(e, value) => updateSettings({ fontSize: value })} + /> + + + + + toFixed(value, 2)} + onChange={(e, value) => + updateSettings({ + lineHeight: value, + }) + } + /> + + + + + + + + + + Import settings + + + + + + + chatRenderer.clearChat()} + > + Clear chat + + + + + ); +} diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.tsx b/tgui/packages/tgui-panel/settings/SettingsPanel.tsx new file mode 100644 index 00000000000..1efcfe8facf --- /dev/null +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.tsx @@ -0,0 +1,54 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { Section, Stack, Tabs } from 'tgui-core/components'; +import { ChatPageSettings } from '../chat/ChatPageSettings'; +import { SETTINGS_TABS } from './constants'; +import { SettingsGeneral } from './SettingsGeneral'; +import { SettingsStatPanel } from './SettingsStatPanel'; +import { TextHighlightSettings } from './TextHighlight'; +import { useSettings } from './use-settings'; + +export function SettingsPanel(props) { + const { + settings: { view }, + updateSettings, + } = useSettings(); + const { activeTab } = view; + + return ( + + +
+ + {SETTINGS_TABS.map((tab) => ( + + updateSettings({ + view: { + ...view, + activeTab: tab.id, + }, + }) + } + > + {tab.name} + + ))} + +
+
+ + {activeTab === 'general' && } + {activeTab === 'chatPage' && } + {activeTab === 'textHighlight' && } + {activeTab === 'statPanel' && } + +
+ ); +} diff --git a/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx b/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx new file mode 100644 index 00000000000..d4a28c1ab33 --- /dev/null +++ b/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx @@ -0,0 +1,77 @@ +import { + Button, + LabeledList, + NoticeBox, + Section, + Slider, + Stack, +} from 'tgui-core/components'; +import { toFixed } from 'tgui-core/math'; +import { capitalize } from 'tgui-core/string'; +import { useSettings } from './use-settings'; + +const tabViews = ['default', 'classic', 'scrollable']; + +function LinkedToChat() { + return Unlink Stat Panel from chat!; +} + +export function SettingsStatPanel(props) { + const { settings, updateSettings } = useSettings(); + const { statLinked, statFontSize, statTabsStyle } = settings; + + return ( +
+ + + + + {tabViews.map((view) => ( + + ))} + + + + {statLinked ? ( + + ) : ( + toFixed(value)} + onChange={(e, value) => + updateSettings({ statFontSize: value }) + } + /> + )} + + + + + + + + + +
+ ); +} diff --git a/tgui/packages/tgui-panel/settings/TextHighlight.tsx b/tgui/packages/tgui-panel/settings/TextHighlight.tsx new file mode 100644 index 00000000000..60c942979d9 --- /dev/null +++ b/tgui/packages/tgui-panel/settings/TextHighlight.tsx @@ -0,0 +1,164 @@ +import { + Box, + Button, + ColorBox, + Divider, + Icon, + Input, + Section, + Stack, + TextArea, +} from 'tgui-core/components'; +import { chatRenderer } from '../chat/renderer'; +import { WARN_AFTER_HIGHLIGHT_AMT } from './constants'; +import { useHighlights } from './use-highlights'; + +export function TextHighlightSettings(props) { + const { + highlights: { highlightSettings }, + addHighlight, + } = useHighlights(); + + return ( +
+ + {highlightSettings.map((id, i) => ( + + ))} + + + + {highlightSettings.length >= WARN_AFTER_HIGHLIGHT_AMT && ( + + + Large amounts of highlights can potentially cause performance + issues! + + )} + + + + + + + + Can freeze the chat for a while. + + +
+ ); +} + +function TextHighlightSetting(props) { + const { id, ...rest } = props; + const { + highlights: { highlightSettingById }, + updateHighlight, + removeHighlight, + } = useHighlights(); + const { + highlightColor, + highlightText, + highlightWholeMessage, + matchWord, + matchCase, + } = highlightSettingById[id]; + + return ( + + + + + + + + updateHighlight({ + id, + highlightWholeMessage: !highlightWholeMessage, + }) + } + > + Whole Message + + + + + updateHighlight({ + id, + matchWord: !matchWord, + }) + } + > + Exact + + + + + updateHighlight({ + id, + matchCase: !matchCase, + }) + } + > + Case + + + + + + updateHighlight({ + id, + highlightColor: value, + }) + } + /> + + +