diff --git a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm index 1c308a0e0b..fb686820ee 100644 --- a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm +++ b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm @@ -140,7 +140,7 @@ /obj/machinery/atmospherics/binary/algae_farm/attack_hand(mob/user) if(..()) return 1 - ui_interact(user) + tgui_interact(user) /obj/machinery/atmospherics/binary/algae_farm/RefreshParts() ..() @@ -165,7 +165,13 @@ moles_per_tick = initial(moles_per_tick) + (manip_rating**2 - 1) -/obj/machinery/atmospherics/binary/algae_farm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = default_state) +/obj/machinery/atmospherics/binary/algae_farm/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AlgaeFarm", name) + ui.open() + +/obj/machinery/atmospherics/binary/algae_farm/tgui_data(mob/user) var/data[0] data["panelOpen"] = panel_open @@ -198,41 +204,28 @@ "percent" = air2.total_moles ? round((air2.gas[output_gas] / air2.total_moles) * 100) : 0, "moles" = round(air2.gas[output_gas], 0.01)) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "algae_farm_vr.tmpl", "Algae Farm Control Panel", 500, 600) - ui.set_initial_data(data) - ui.set_auto_update(TRUE) - ui.open() + return data -/obj/machinery/atmospherics/binary/algae_farm/Topic(href, href_list) +/obj/machinery/atmospherics/binary/algae_farm/tgui_act(action, params) if(..()) - return 1 - usr.set_machine(src) + return TRUE add_fingerprint(usr) - // Queue management can be done even while busy - if(href_list["activate"]) - update_use_power(USE_POWER_ACTIVE) - update_icon() - updateUsrDialog() - return - - if(href_list["deactivate"]) - update_use_power(USE_POWER_IDLE) - update_icon() - updateUsrDialog() - return - - if(href_list["ejectMaterial"]) - var/matName = href_list["ejectMaterial"] - if(!(matName in stored_material)) - return - eject_materials(matName, 0) - updateUsrDialog() - return + switch(action) + if("toggle") + if(use_power == USE_POWER_IDLE) + update_use_power(USE_POWER_ACTIVE) + else + update_use_power(USE_POWER_IDLE) + update_icon() + . = TRUE + if("ejectMaterial") + var/matName = params["mat"] + if(!(matName in stored_material)) + return + eject_materials(matName, 0) + . = TRUE // TODO - These should be replaced with materials datum. diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index 1c501e87f0..dd38dae3ca 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -209,18 +209,21 @@ /obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) + add_fingerprint(usr) + if(!allowed(user)) to_chat(user, "Access denied.") return - usr.set_machine(src) - ui_interact(user) - return + tgui_interact(user) -/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/atmospherics/binary/passive_gate/tgui_interact(mob/user, datum/tgui/ui) if(stat & (BROKEN|NOPOWER)) - return + return FALSE + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PressureRegulator", name) + ui.open() +/obj/machinery/atmospherics/binary/passive_gate/tgui_data(mob/user) // this is the data which will be sent to the ui var/data[0] @@ -235,51 +238,48 @@ "last_flow_rate" = round(last_flow_rate*10), ) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "pressure_regulator.tmpl", name, 470, 370) - ui.set_initial_data(data) // when the ui is first opened this is the data it will use - ui.open() // open the new ui window - ui.set_auto_update(1) // auto update every Master Controller tick + return data -/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list) - if(..()) return 1 +/obj/machinery/atmospherics/binary/passive_gate/tgui_act(action, params) + if(..()) + return TRUE - if(href_list["toggle_valve"]) - unlocked = !unlocked + switch(action) + if("toggle_valve") + . = TRUE + unlocked = !unlocked + if("regulate_mode") + . = TRUE + switch(params["mode"]) + if("off") regulate_mode = REGULATE_NONE + if("input") regulate_mode = REGULATE_INPUT + if("output") regulate_mode = REGULATE_OUTPUT - if(href_list["regulate_mode"]) - switch(href_list["regulate_mode"]) - if ("off") regulate_mode = REGULATE_NONE - if ("input") regulate_mode = REGULATE_INPUT - if ("output") regulate_mode = REGULATE_OUTPUT + if("set_press") + . = TRUE + switch(params["press"]) + if("min") + target_pressure = 0 + if("max") + target_pressure = max_pressure_setting + if("set") + var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure) as num + src.target_pressure = between(0, new_pressure, max_pressure_setting) - switch(href_list["set_press"]) - if ("min") - target_pressure = 0 - if ("max") - target_pressure = max_pressure_setting - if ("set") - var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure) as num - src.target_pressure = between(0, new_pressure, max_pressure_setting) + if("set_flow_rate") + . = TRUE + switch(params["press"]) + if("min") + set_flow_rate = 0 + if("max") + set_flow_rate = air1.volume + if("set") + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num + src.set_flow_rate = between(0, new_flow_rate, air1.volume) - switch(href_list["set_flow_rate"]) - if ("min") - set_flow_rate = 0 - if ("max") - set_flow_rate = air1.volume - if ("set") - var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]kPa)","Flow Rate Control",src.set_flow_rate) as num - src.set_flow_rate = between(0, new_flow_rate, air1.volume) - - usr.set_machine(src) //Is this even needed with NanoUI? - src.update_icon() - src.add_fingerprint(usr) - return + update_icon() + add_fingerprint(usr) /obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) if (!W.is_wrench()) diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm index 0df0217497..54e034dc92 100644 --- a/code/ATMOSPHERICS/components/binary_devices/pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -143,10 +143,15 @@ Thus, the two variables affect pump operation are set in New(): return 1 -/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/atmospherics/binary/pump/tgui_interact(mob/user, datum/tgui/ui) if(stat & (BROKEN|NOPOWER)) return + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GasPump", name) + ui.open() +/obj/machinery/atmospherics/binary/pump/tgui_data(mob/user) // this is the data which will be sent to the ui var/data[0] @@ -159,15 +164,7 @@ Thus, the two variables affect pump operation are set in New(): "max_power_draw" = power_rating, ) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "gas_pump.tmpl", name, 470, 290) - ui.set_initial_data(data) // when the ui is first opened this is the data it will use - ui.open() // open the new ui window - ui.set_auto_update(1) // auto update every Master Controller tick + return data /obj/machinery/atmospherics/binary/pump/Initialize() . = ..() @@ -204,36 +201,40 @@ Thus, the two variables affect pump operation are set in New(): update_icon() return -/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob) +/obj/machinery/atmospherics/binary/pump/attack_ghost(mob/user) + tgui_interact(user) + +/obj/machinery/atmospherics/binary/pump/attack_hand(mob/user) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) + add_fingerprint(usr) + if(!allowed(user)) to_chat(user, "Access denied.") return - usr.set_machine(src) - ui_interact(user) - return + tgui_interact(user) -/obj/machinery/atmospherics/binary/pump/Topic(href,href_list) - if(..()) return 1 +/obj/machinery/atmospherics/binary/pump/tgui_act(action, params) + if(..()) + return TRUE - if(href_list["power"]) - update_use_power(!use_power) + switch(action) + if("power") + update_use_power(!use_power) + . = TRUE + if("set_press") + var/press = params["press"] + switch(press) + if("min") + target_pressure = 0 + if("max") + target_pressure = max_pressure_setting + if("set") + var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num + src.target_pressure = between(0, new_pressure, max_pressure_setting) + . = TRUE - switch(href_list["set_press"]) - if ("min") - target_pressure = 0 - if ("max") - target_pressure = max_pressure_setting - if ("set") - var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = between(0, new_pressure, max_pressure_setting) - - usr.set_machine(src) - src.add_fingerprint(usr) - - src.update_icon() + add_fingerprint(usr) + update_icon() /obj/machinery/atmospherics/binary/pump/power_change() var/old_stat = stat diff --git a/code/ATMOSPHERICS/components/omni_devices/filter.dm b/code/ATMOSPHERICS/components/omni_devices/filter.dm index 9f0862d800..56171a0880 100644 --- a/code/ATMOSPHERICS/components/omni_devices/filter.dm +++ b/code/ATMOSPHERICS/components/omni_devices/filter.dm @@ -87,23 +87,14 @@ return 1 -/obj/machinery/atmospherics/omni/atmos_filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - var/list/data = new() - - data = build_uidata() - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330) - ui.set_initial_data(data) - +/obj/machinery/atmospherics/omni/atmos_filter/tgui_interact(mob/user,datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "OmniFilter", name) ui.open() -/obj/machinery/atmospherics/omni/atmos_filter/proc/build_uidata() - var/list/data = new() +/obj/machinery/atmospherics/omni/atmos_filter/tgui_data(mob/user) + var/list/data = list() data["power"] = use_power data["config"] = configuring @@ -156,34 +147,41 @@ else return null -/obj/machinery/atmospherics/omni/atmos_filter/Topic(href, href_list) - if(..()) return 1 - switch(href_list["command"]) +/obj/machinery/atmospherics/omni/atmos_filter/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) if("power") if(!configuring) update_use_power(!use_power) else update_use_power(USE_POWER_OFF) + . = TRUE if("configure") configuring = !configuring if(configuring) update_use_power(USE_POWER_OFF) - - //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on - if(configuring && !use_power) - switch(href_list["command"]) - if("set_flow_rate") - var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num - set_flow_rate = between(0, new_flow_rate, max_flow_rate) - if("switch_mode") - switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"])) - if("switch_filter") - var/new_filter = input(usr,"Select filter mode:","Change filter",href_list["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Phoron", "Nitrous Oxide") - switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter)) + . = TRUE + if("set_flow_rate") + if(!configuring || use_power) + return + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num + set_flow_rate = between(0, new_flow_rate, max_flow_rate) + . = TRUE + if("switch_mode") + if(!configuring || use_power) + return + switch_mode(dir_flag(params["dir"]), mode_return_switch(params["mode"])) + . = TRUE + if("switch_filter") + if(!configuring || use_power) + return + var/new_filter = input(usr,"Select filter mode:","Change filter",params["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Phoron", "Nitrous Oxide") + switch_filter(dir_flag(params["dir"]), mode_return_switch(new_filter)) + . = TRUE update_icon() - SSnanoui.update_uis(src) - return /obj/machinery/atmospherics/omni/atmos_filter/proc/mode_return_switch(var/mode) switch(mode) diff --git a/code/ATMOSPHERICS/components/omni_devices/mixer.dm b/code/ATMOSPHERICS/components/omni_devices/mixer.dm index 0210d09e69..077be63b30 100644 --- a/code/ATMOSPHERICS/components/omni_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/omni_devices/mixer.dm @@ -124,22 +124,13 @@ return 1 -/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - usr.set_machine(src) - - var/list/data = new() - - data = build_uidata() - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330) - ui.set_initial_data(data) - +/obj/machinery/atmospherics/omni/mixer/tgui_interact(mob/user,datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "OmniMixer", name) ui.open() -/obj/machinery/atmospherics/omni/mixer/proc/build_uidata() +/obj/machinery/atmospherics/omni/mixer/tgui_data(mob/user) var/list/data = new() data["power"] = use_power @@ -172,36 +163,45 @@ return data -/obj/machinery/atmospherics/omni/mixer/Topic(href, href_list) - if(..()) return 1 +/obj/machinery/atmospherics/omni/mixer/tgui_act(action, params) + if(..()) + return TRUE - switch(href_list["command"]) + switch(action) if("power") + . = TRUE if(!configuring) update_use_power(!use_power) else update_use_power(USE_POWER_OFF) if("configure") + . = TRUE configuring = !configuring if(configuring) update_use_power(USE_POWER_OFF) - - //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on - if(configuring && !use_power) - switch(href_list["command"]) - if("set_flow_rate") - var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num - set_flow_rate = between(0, new_flow_rate, max_flow_rate) - if("switch_mode") - switch_mode(dir_flag(href_list["dir"]), href_list["mode"]) - if("switch_con") - change_concentration(dir_flag(href_list["dir"])) - if("switch_conlock") - con_lock(dir_flag(href_list["dir"])) + if("set_flow_rate") + . = TRUE + if(!configuring || use_power) + return + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num + set_flow_rate = between(0, new_flow_rate, max_flow_rate) + if("switch_mode") + . = TRUE + if(!configuring || use_power) + return + switch_mode(dir_flag(params["dir"]), params["mode"]) + if("switch_con") + . = TRUE + if(!configuring || use_power) + return + change_concentration(dir_flag(params["dir"])) + if("switch_conlock") + . = TRUE + if(!configuring || use_power) + return + con_lock(dir_flag(params["dir"])) update_icon() - SSnanoui.update_uis(src) - return /obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE) if(mode != ATM_INPUT && mode != ATM_OUTPUT) diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm index 54acc3db99..be7f905a77 100644 --- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm +++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm @@ -110,7 +110,7 @@ return src.add_fingerprint(usr) - ui_interact(user) + tgui_interact(user) return /obj/machinery/atmospherics/omni/proc/build_icons() diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index bde060a11a..e2aaee092c 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -111,7 +111,7 @@ if(frequency) set_frequency(frequency) -/obj/machinery/atmospherics/trinary/atmos_filter/attack_hand(user as mob) // -- TLE +/obj/machinery/atmospherics/trinary/atmos_filter/attack_hand(user) // -- TLE if(..()) return @@ -119,81 +119,106 @@ to_chat(user, "Access denied.") return - var/dat - var/current_filter_type - switch(filter_type) - if(0) - current_filter_type = "Phoron" - if(1) - current_filter_type = "Oxygen" - if(2) - current_filter_type = "Nitrogen" - if(3) - current_filter_type = "Carbon Dioxide" - if(4) - current_filter_type = "Nitrous Oxide" - if(-1) - current_filter_type = "Nothing" - else - current_filter_type = "ERROR - Report this bug to the admin, please!" + tgui_interact(user) - dat += {" - Power: [use_power?"On":"Off"]
- Filtering: [current_filter_type]

-

Set Filter Type:

- Phoron
- Oxygen
- Nitrogen
- Carbon Dioxide
- Nitrous Oxide
- Nothing
-
- Set Flow Rate Limit: - [src.set_flow_rate]L/s | Change
- Flow rate: [round(last_flow_rate, 0.1)]L/s - "} + // var/dat + // var/current_filter_type + // switch(filter_type) + // if(0) + // current_filter_type = "Phoron" + // if(1) + // current_filter_type = "Oxygen" + // if(2) + // current_filter_type = "Nitrogen" + // if(3) + // current_filter_type = "Carbon Dioxide" + // if(4) + // current_filter_type = "Nitrous Oxide" + // if(-1) + // current_filter_type = "Nothing" + // else + // current_filter_type = "ERROR - Report this bug to the admin, please!" - user << browse("[src.name] control[dat]", "window=atmos_filter") - onclose(user, "atmos_filter") - return + // dat += {" + // Power: [use_power?"On":"Off"]
+ // Filtering: [current_filter_type]

+ //

Set Filter Type:

+ // Phoron
+ // Oxygen
+ // Nitrogen
+ // Carbon Dioxide
+ // Nitrous Oxide
+ // Nothing
+ //
+ // Set Flow Rate Limit: + // [src.set_flow_rate]L/s | Change
+ // Flow rate: [round(last_flow_rate, 0.1)]L/s + // "} -/obj/machinery/atmospherics/trinary/atmos_filter/Topic(href, href_list) // -- TLE + // user << browse("[src.name] control[dat]", "window=atmos_filter") + // onclose(user, "atmos_filter") + + + +/obj/machinery/atmospherics/trinary/atmos_filter/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AtmosFilter", name) + ui.open() + +/obj/machinery/atmospherics/trinary/atmos_filter/tgui_data(mob/user) + var/list/data = list() + + data["on"] = use_power + data["rate"] = set_flow_rate + data["max_rate"] = air1.volume + + data["filter_types"] = list() + data["filter_types"] += list(list("name" = "Nothing", "f_type" = -1, "selected" = filter_type == -1)) + data["filter_types"] += list(list("name" = "Phoron", "f_type" = 0, "selected" = filter_type == 0)) + data["filter_types"] += list(list("name" = "Oxygen", "f_type" = 1, "selected" = filter_type == 1)) + data["filter_types"] += list(list("name" = "Nitrogen", "f_type" = 2, "selected" = filter_type == 2)) + data["filter_types"] += list(list("name" = "Carbon Dioxide", "f_type" = 3, "selected" = filter_type == 3)) + data["filter_types"] += list(list("name" = "Nitrous Oxide", "f_type" = 4, "selected" = filter_type == 4)) + + return data + +/obj/machinery/atmospherics/trinary/atmos_filter/tgui_act(action, params) if(..()) - return 1 - usr.set_machine(src) - src.add_fingerprint(usr) - if(href_list["filterset"]) - filter_type = text2num(href_list["filterset"]) + return TRUE - filtered_out.Cut() //no need to create new lists unnecessarily - switch(filter_type) - if(0) //removing hydrocarbons - filtered_out += "phoron" - filtered_out += "oxygen_agent_b" - if(1) //removing O2 - filtered_out += "oxygen" - if(2) //removing N2 - filtered_out += "nitrogen" - if(3) //removing CO2 - filtered_out += "carbon_dioxide" - if(4)//removing N2O - filtered_out += "sleeping_agent" + switch(action) + if("power") + update_use_power(!use_power) + if("rate") + var/rate = params["rate"] + if(rate == "max") + rate = air1.volume + . = TRUE + else if(text2num(rate) != null) + rate = text2num(rate) + . = TRUE + if(.) + set_flow_rate = clamp(rate, 0, air1.volume) + if("filter") + . = TRUE + filter_type = text2num(params["filterset"]) + filtered_out.Cut() //no need to create new lists unnecessarily + switch(filter_type) + if(0) //removing hydrocarbons + filtered_out += "phoron" + filtered_out += "oxygen_agent_b" + if(1) //removing O2 + filtered_out += "oxygen" + if(2) //removing N2 + filtered_out += "nitrogen" + if(3) //removing CO2 + filtered_out += "carbon_dioxide" + if(4)//removing N2O + filtered_out += "sleeping_agent" - if (href_list["temp"]) - src.temp = null - if(href_list["set_flow_rate"]) - var/new_flow_rate = input(usr,"Enter new flow rate (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num - src.set_flow_rate = max(0, min(air1.volume, new_flow_rate)) - if(href_list["power"]) - update_use_power(!use_power) - src.update_icon() - src.updateUsrDialog() -/* - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) -*/ - return + add_fingerprint(usr) + update_icon() // // Mirrored Orientation - Flips the output dir to opposite side from normal. diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index 62b4b763b8..ef2a4c1a8a 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -77,59 +77,88 @@ return 1 +/obj/machinery/atmospherics/trinary/mixer/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AtmosMixer", name) + ui.open() + +/obj/machinery/atmospherics/trinary/mixer/tgui_data(mob/user) + var/list/data = list() + data["on"] = use_power + data["set_pressure"] = round(set_flow_rate) + data["max_pressure"] = min(air1.volume, air2.volume) + data["node1_concentration"] = round(mixing_inputs[air1]*100, 1) + data["node2_concentration"] = round(mixing_inputs[air2]*100, 1) + var/list/node_connects = get_node_connect_dirs() + data["node1_dir"] = dir_name(node_connects[1],TRUE) + data["node2_dir"] = dir_name(node_connects[2],TRUE) + return data + /obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) - to_chat(user, "Access denied.") - return - usr.set_machine(src) - var/list/node_connects = get_node_connect_dirs() - var/dat = {"Power: [use_power?"On":"Off"]
- Set Flow Rate Limit: - [set_flow_rate]L/s | Change -
- Flow Rate: [round(last_flow_rate, 0.1)]L/s -

- Node 1 ([dir_name(node_connects[1],TRUE)]) Concentration: - - - - - [mixing_inputs[air1]]([mixing_inputs[air1]*100]%) - + - + -
- Node 2 ([dir_name(node_connects[2],TRUE)]) Concentration: - - - - - [mixing_inputs[air2]]([mixing_inputs[air2]*100]%) - + - + - "} + tgui_interact(user) + // src.add_fingerprint(usr) + // if(!src.allowed(user)) + // to_chat(user, "Access denied.") + // return + // usr.set_machine(src) + // var/list/node_connects = get_node_connect_dirs() + // var/dat = {"Power: [use_power?"On":"Off"]
+ // Set Flow Rate Limit: + // [set_flow_rate]L/s | Change + //
+ // Flow Rate: [round(last_flow_rate, 0.1)]L/s + //

+ // Node 1 ([dir_name(node_connects[1],TRUE)]) Concentration: + // - + // - + // [mixing_inputs[air1]]([mixing_inputs[air1]*100]%) + // + + // + + //
+ // Node 2 ([dir_name(node_connects[2],TRUE)]) Concentration: + // - + // - + // [mixing_inputs[air2]]([mixing_inputs[air2]*100]%) + // + + // + + // "} - user << browse("[src.name] control[dat]", "window=atmo_mixer") - onclose(user, "atmo_mixer") - return + // user << browse("[src.name] control[dat]", "window=atmo_mixer") + // onclose(user, "atmo_mixer") + // return -/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list) - if(..()) return 1 - if(href_list["power"]) - update_use_power(!use_power) - if(href_list["set_press"]) - var/max_flow_rate = min(air1.volume, air2.volume) - var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num - src.set_flow_rate = max(0, min(max_flow_rate, new_flow_rate)) - if(href_list["node1_c"]) - var/value = text2num(href_list["node1_c"]) - src.mixing_inputs[air1] = max(0, min(1, src.mixing_inputs[air1] + value)) - src.mixing_inputs[air2] = 1.0 - mixing_inputs[air1] - if(href_list["node2_c"]) - var/value = text2num(href_list["node2_c"]) - src.mixing_inputs[air2] = max(0, min(1, src.mixing_inputs[air2] + value)) - src.mixing_inputs[air1] = 1.0 - mixing_inputs[air2] - src.update_icon() - src.updateUsrDialog() - return +/obj/machinery/atmospherics/trinary/mixer/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("power") + update_use_power(!use_power) + . = TRUE + if("pressure") + var/pressure = params["pressure"] + if(pressure == "max") + pressure = min(air1.volume, air2.volume) + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + set_flow_rate = clamp(pressure, 0, min(air1.volume, air2.volume)) + if("node1") + var/value = text2num(params["concentration"]) + mixing_inputs[air1] = max(0, min(1, value / 100)) + mixing_inputs[air2] = 1.0 - mixing_inputs[air1] + . = TRUE + if("node2") + var/value = text2num(params["concentration"]) + mixing_inputs[air2] = max(0, min(1, value / 100)) + mixing_inputs[air1] = 1.0 - mixing_inputs[air2] + . = TRUE + update_icon() // // "T" Orientation - Inputs are on oposite sides instead of adjacent diff --git a/code/ATMOSPHERICS/components/unary/cold_sink.dm b/code/ATMOSPHERICS/components/unary/cold_sink.dm index 2c53c47583..3568a87a42 100644 --- a/code/ATMOSPHERICS/components/unary/cold_sink.dm +++ b/code/ATMOSPHERICS/components/unary/cold_sink.dm @@ -53,12 +53,18 @@ return /obj/machinery/atmospherics/unary/freezer/attack_ai(mob/user as mob) - ui_interact(user) + tgui_interact(user) /obj/machinery/atmospherics/unary/freezer/attack_hand(mob/user as mob) - ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/unary/freezer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/atmospherics/unary/freezer/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GasTemperatureSystem", name) + ui.open() + +/obj/machinery/atmospherics/unary/freezer/tgui_data(mob/user) // this is the data which will be sent to the ui var/data[0] data["on"] = use_power ? 1 : 0 @@ -76,34 +82,26 @@ temp_class = "average" data["gasTemperatureClass"] = temp_class - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "freezer.tmpl", "Gas Cooling System", 440, 300) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + return data -/obj/machinery/atmospherics/unary/freezer/Topic(href, href_list) +/obj/machinery/atmospherics/unary/freezer/tgui_act(action, params) if(..()) - return 1 - if(href_list["toggleStatus"]) - update_use_power(!use_power) - update_icon() - if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - set_temperature = min(set_temperature + amount, 1000) - else - set_temperature = max(set_temperature + amount, 0) - if(href_list["setPower"]) //setting power to 0 is redundant anyways - var/new_setting = between(0, text2num(href_list["setPower"]), 100) - set_power_level(new_setting) + return TRUE + + . = TRUE + switch(action) + if("toggleStatus") + update_use_power(!use_power) + update_icon() + if("setGasTemperature") + var/amount = text2num(params["temp"]) + if(amount > 0) + set_temperature = min(amount, 1000) + else + set_temperature = max(amount, 0) + if("setPower") //setting power to 0 is redundant anyways + var/new_setting = between(0, text2num(params["value"]), 100) + set_power_level(new_setting) add_fingerprint(usr) diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm index ad852affdc..365be85b70 100644 --- a/code/ATMOSPHERICS/components/unary/heat_source.dm +++ b/code/ATMOSPHERICS/components/unary/heat_source.dm @@ -75,12 +75,18 @@ update_icon() /obj/machinery/atmospherics/unary/heater/attack_ai(mob/user as mob) - ui_interact(user) + tgui_interact(user) /obj/machinery/atmospherics/unary/heater/attack_hand(mob/user as mob) - ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/unary/heater/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/atmospherics/unary/heater/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GasTemperatureSystem", name) + ui.open() + +/obj/machinery/atmospherics/unary/heater/tgui_data(mob/user) // this is the data which will be sent to the ui var/data[0] data["on"] = use_power ? 1 : 0 @@ -91,39 +97,31 @@ data["targetGasTemperature"] = round(set_temperature) data["powerSetting"] = power_setting - var/temp_class = "normal" + var/temp_class = "average" if(air_contents.temperature > (T20C+40)) temp_class = "bad" data["gasTemperatureClass"] = temp_class - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "freezer.tmpl", "Gas Heating System", 440, 300) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + return data -/obj/machinery/atmospherics/unary/heater/Topic(href, href_list) +/obj/machinery/atmospherics/unary/heater/tgui_act(action, params) if(..()) - return 1 - if(href_list["toggleStatus"]) - update_use_power(!use_power) - update_icon() - if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - set_temperature = min(set_temperature + amount, max_temperature) - else - set_temperature = max(set_temperature + amount, 0) - if(href_list["setPower"]) //setting power to 0 is redundant anyways - var/new_setting = between(0, text2num(href_list["setPower"]), 100) - set_power_level(new_setting) + return TRUE + + . = TRUE + switch(action) + if("toggleStatus") + update_use_power(!use_power) + update_icon() + if("setGasTemperature") + var/amount = text2num(params["temp"]) + if(amount > 0) + set_temperature = min(amount, max_temperature) + else + set_temperature = max(amount, 0) + if("setPower") //setting power to 0 is redundant anyways + var/new_setting = between(0, text2num(params["value"]), 100) + set_power_level(new_setting) add_fingerprint(usr) diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm index 593d3cbd8b..792d53d65d 100644 --- a/code/ATMOSPHERICS/components/unary/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -374,6 +374,12 @@ ONE_ATMOSPHERE*50 ) + if("reset_external_pressure" in signal.data) + external_pressure_bound = ONE_ATMOSPHERE + + if("reset_internal_pressure" in signal.data) + internal_pressure_bound = 0 + if(signal.data["init"] != null) name = signal.data["init"] return diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 79b82bfe22..4e333dac06 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -58,6 +58,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_MAPPING 25 #define INIT_ORDER_DECALS 20 #define INIT_ORDER_JOB 17 +#define INIT_ORDER_ALARM 16 // Must initialize before atoms. #define INIT_ORDER_ATOMS 15 #define INIT_ORDER_MACHINES 10 #define INIT_ORDER_SHUTTLES 3 @@ -70,7 +71,6 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_HOLOMAPS -5 #define INIT_ORDER_NIGHTSHIFT -6 #define INIT_ORDER_OVERLAY -7 -#define INIT_ORDER_ALARM -8 #define INIT_ORDER_OPENSPACE -10 #define INIT_ORDER_XENOARCH -20 #define INIT_ORDER_CIRCUIT -21 diff --git a/code/datums/autolathe/general.dm b/code/datums/autolathe/general.dm index 2513a47337..a2dcd047c9 100644 --- a/code/datums/autolathe/general.dm +++ b/code/datums/autolathe/general.dm @@ -103,12 +103,14 @@ path =/obj/item/stack/material/plasteel is_stack = TRUE no_scale = TRUE //prevents material duplication exploits + resources = list(MAT_PLASTEEL = 2000) /datum/category_item/autolathe/general/plastic name = "plastic sheets" path =/obj/item/stack/material/plastic is_stack = TRUE no_scale = TRUE //prevents material duplication exploits + resources = list(MAT_PLASTIC = 2000) //TFF 24/12/19 - Let people print more spray bottles if needed. /datum/category_item/autolathe/general/spraybottle diff --git a/code/datums/outfits/outfit.dm b/code/datums/outfits/outfit.dm index 846b519f77..a2d3e9b728 100644 --- a/code/datums/outfits/outfit.dm +++ b/code/datums/outfits/outfit.dm @@ -101,6 +101,7 @@ var/list/outfits_decls_by_type_ H.equip_to_slot_or_del(new path(H), slot_in_backpack) post_equip(H) + if(W) // We set ID info last to ensure the ID photo is as correct as possible. H.set_id_info(W) return 1 diff --git a/code/game/antagonist/antagonist_update.dm b/code/game/antagonist/antagonist_update.dm index 16c27f82c7..b118cb91db 100644 --- a/code/game/antagonist/antagonist_update.dm +++ b/code/game/antagonist/antagonist_update.dm @@ -15,7 +15,7 @@ spawn(3) var/mob/living/carbon/human/H = player.current if(istype(H)) - H.change_appearance(APPEARANCE_ALL, H.loc, H, species_whitelist = valid_species, state = z_state) + H.change_appearance(APPEARANCE_ALL, H, species_whitelist = valid_species, state = GLOB.tgui_self_state) return player.current /datum/antagonist/proc/update_access(var/mob/living/player) diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm index b410a40a64..041e43b905 100644 --- a/code/game/machinery/air_alarm.dm +++ b/code/game/machinery/air_alarm.dm @@ -125,6 +125,7 @@ // breathable air according to human/Life() TLV["oxygen"] = list(16, 19, 135, 140) // Partial pressure, kpa + TLV["nitrogen"] = list(0, 0,135,140) // Partial pressure, kpa TLV["carbon dioxide"] = list(-1.0, -1.0, 5, 10) // Partial pressure, kpa TLV["phoron"] = list(-1.0, -1.0, 0, 0.5) // Partial pressure, kpa TLV["other"] = list(-1.0, -1.0, 0.5, 1.0) // Partial pressure, kpa @@ -463,7 +464,7 @@ frequency.post_signal(src, alert_signal) /obj/machinery/alarm/attack_ai(mob/user) - ui_interact(user) + tgui_interact(user) /obj/machinery/alarm/attack_hand(mob/user) . = ..() @@ -472,157 +473,150 @@ return interact(user) /obj/machinery/alarm/interact(mob/user) - ui_interact(user) + tgui_interact(user) wires.Interact(user) -/obj/machinery/alarm/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state) - var/data[0] - var/remote_connection = 0 - var/remote_access = 0 - if(state) - var/list/href = state.href_list(user) - remote_connection = href["remote_connection"] // Remote connection means we're non-adjacent/connecting from another computer - remote_access = href["remote_access"] // Remote access means we also have the privilege to alter the air alarm. +/obj/machinery/alarm/tgui_status(mob/user) + if(isAI(user) && aidisabled) + to_chat(user, "AI control has been disabled.") + else if(!shorted) + return ..() + return STATUS_CLOSE - data["locked"] = locked && !issilicon(user) - data["remote_connection"] = remote_connection - data["remote_access"] = remote_access - data["rcon"] = rcon_setting - data["screen"] = screen - - populate_status(data) - - if(!(locked && !remote_connection) || remote_access || issilicon(user)) - populate_controls(data) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) +/obj/machinery/alarm/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/tgui_state/state) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "air_alarm.tmpl", name, 325, 625, master_ui = master_ui, state = state) - ui.set_initial_data(data) + ui = new(user, src, "AirAlarm", name, parent_ui) + if(state) + ui.set_state(state) ui.open() - ui.set_auto_update(1) -/obj/machinery/alarm/proc/populate_status(var/data) - var/turf/location = get_turf(src) - var/datum/gas_mixture/environment = location.return_air() - var/total = environment.total_moles +/obj/machinery/alarm/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = list( + "locked" = locked, + "siliconUser" = issilicon(user), + "remoteUser" = !!ui.parent_ui, + "danger_level" = danger_level, + "target_temperature" = "[target_temperature - T0C]C", + "rcon" = rcon_setting, + ) - var/list/environment_data = new - data["has_environment"] = total - if(total) - var/pressure = environment.return_pressure() - environment_data[++environment_data.len] = list("name" = "Pressure", "value" = pressure, "unit" = "kPa", "danger_level" = pressure_dangerlevel) - environment_data[++environment_data.len] = list("name" = "Oxygen", "value" = environment.gas["oxygen"] / total * 100, "unit" = "%", "danger_level" = oxygen_dangerlevel) - environment_data[++environment_data.len] = list("name" = "Carbon dioxide", "value" = environment.gas["carbon_dioxide"] / total * 100, "unit" = "%", "danger_level" = co2_dangerlevel) - environment_data[++environment_data.len] = list("name" = "Toxins", "value" = environment.gas["phoron"] / total * 100, "unit" = "%", "danger_level" = phoron_dangerlevel) - environment_data[++environment_data.len] = list("name" = "Temperature", "value" = environment.temperature, "unit" = "K ([round(environment.temperature - T0C, 0.1)]C)", "danger_level" = temperature_dangerlevel) - data["total_danger"] = danger_level - data["environment"] = environment_data - data["atmos_alarm"] = alarm_area.atmosalm - data["fire_alarm"] = alarm_area.fire != null - data["target_temperature"] = "[target_temperature - T0C]C" + var/area/A = get_area(src) + data["atmos_alarm"] = A?.atmosalm + data["fire_alarm"] = A?.fire -/obj/machinery/alarm/proc/populate_controls(var/list/data) - switch(screen) - if(AALARM_SCREEN_MAIN) - data["mode"] = mode - if(AALARM_SCREEN_VENT) - var/vents[0] - for(var/id_tag in alarm_area.air_vent_names) - var/long_name = alarm_area.air_vent_names[id_tag] - var/list/info = alarm_area.air_vent_info[id_tag] - if(!info) - continue - vents[++vents.len] = list( - "id_tag" = id_tag, - "long_name" = sanitize(long_name), - "power" = info["power"], - "checks" = info["checks"], - "direction" = info["direction"], - "external" = info["external"] - ) - data["vents"] = vents - if(AALARM_SCREEN_SCRUB) - var/scrubbers[0] - for(var/id_tag in alarm_area.air_scrub_names) - var/long_name = alarm_area.air_scrub_names[id_tag] - var/list/info = alarm_area.air_scrub_info[id_tag] - if(!info) - continue - scrubbers[++scrubbers.len] = list( - "id_tag" = id_tag, - "long_name" = sanitize(long_name), - "power" = info["power"], - "scrubbing" = info["scrubbing"], - "panic" = info["panic"], - "filters" = list() - ) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Oxygen", "command" = "o2_scrub", "val" = info["filter_o2"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Nitrogen", "command" = "n2_scrub", "val" = info["filter_n2"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Carbon Dioxide", "command" = "co2_scrub","val" = info["filter_co2"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Toxin" , "command" = "tox_scrub","val" = info["filter_phoron"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Nitrous Oxide", "command" = "n2o_scrub","val" = info["filter_n2o"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Fuel", "command" = "fuel_scrub","val" = info["filter_fuel"])) - data["scrubbers"] = scrubbers - if(AALARM_SCREEN_MODE) - var/modes[0] - modes[++modes.len] = list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0) - modes[++modes.len] = list("name" = "Replace Air - Siphons out air while replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 0) - modes[++modes.len] = list("name" = "Panic - Siphons air out of the room", "mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1) - modes[++modes.len] = list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_CYCLE, "selected" = mode == AALARM_MODE_CYCLE, "danger" = 1) - modes[++modes.len] = list("name" = "Fill - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FILL, "selected" = mode == AALARM_MODE_FILL, "danger" = 0) - modes[++modes.len] = list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0) - data["modes"] = modes - data["mode"] = mode - if(AALARM_SCREEN_SENSORS) - var/list/selected - var/thresholds[0] + var/turf/T = get_turf(src) + var/datum/gas_mixture/environment = T.return_air() - var/list/gas_names = list( - "oxygen" = "O2", - "carbon dioxide" = "CO2", - "phoron" = "Toxin", - "other" = "Other") - for(var/g in gas_names) - thresholds[++thresholds.len] = list("name" = gas_names[g], "settings" = list()) - selected = TLV[g] - for(var/i = 1, i <= 4, i++) - thresholds[thresholds.len]["settings"] += list(list("env" = g, "val" = i, "selected" = selected[i])) + data["environment_data"] = list() + var/pressure = environment.return_pressure() + data["environment_data"] += list(list( + "name" = "Pressure", + "value" = pressure, + "unit" = "kPa", + "danger_level" = get_danger_level(pressure, TLV["pressure"]) + )) + var/temperature = environment.temperature + data["environment_data"] += list(list( + "name" = "Temperature", + "value" = temperature, + "unit" = "K ([round(temperature - T0C, 0.1)]C)", + "danger_level" = get_danger_level(temperature, TLV["temperature"]) + )) - selected = TLV["pressure"] - thresholds[++thresholds.len] = list("name" = "Pressure", "settings" = list()) + var/total_moles = environment.total_moles + var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume + for(var/gas_id in environment.gas) + if(!(gas_id in TLV)) + continue + data["environment_data"] += list(list( + "name" = gas_id, + "value" = environment.gas[gas_id] / total_moles * 100, + "unit" = "%", + "danger_level" = get_danger_level(environment.gas[gas_id] * partial_pressure, TLV[gas_id]) + )) + + if(!locked || issilicon(user) || data["remoteUser"]) + data["vents"] = list() + for(var/id_tag in A.air_vent_names) + var/long_name = A.air_vent_names[id_tag] + var/list/info = A.air_vent_info[id_tag] + if(!info) + continue + data["vents"] += list(list( + "id_tag" = id_tag, + "long_name" = sanitize(long_name), + "power" = info["power"], + "checks" = info["checks"], + "excheck" = info["checks"]&1, + "incheck" = info["checks"]&2, + "direction" = info["direction"], + "external" = info["external"], + "internal" = info["internal"], + "extdefault"= (info["external"] == ONE_ATMOSPHERE), + "intdefault"= (info["internal"] == 0), + )) + + data["scrubbers"] = list() + for(var/id_tag in alarm_area.air_scrub_names) + var/long_name = alarm_area.air_scrub_names[id_tag] + var/list/info = alarm_area.air_scrub_info[id_tag] + if(!info) + continue + data["scrubbers"] += list(list( + "id_tag" = id_tag, + "long_name" = sanitize(long_name), + "power" = info["power"], + "scrubbing" = info["scrubbing"], + "panic" = info["panic"], + "filters" = list() + )) + data["scrubbers"][data["scrubbers"].len]["filters"] += list(list("name" = "Oxygen", "command" = "o2_scrub", "val" = info["filter_o2"])) + data["scrubbers"][data["scrubbers"].len]["filters"] += list(list("name" = "Nitrogen", "command" = "n2_scrub", "val" = info["filter_n2"])) + data["scrubbers"][data["scrubbers"].len]["filters"] += list(list("name" = "Carbon Dioxide", "command" = "co2_scrub","val" = info["filter_co2"])) + data["scrubbers"][data["scrubbers"].len]["filters"] += list(list("name" = "Toxin" , "command" = "tox_scrub","val" = info["filter_phoron"])) + data["scrubbers"][data["scrubbers"].len]["filters"] += list(list("name" = "Nitrous Oxide", "command" = "n2o_scrub","val" = info["filter_n2o"])) + data["scrubbers"][data["scrubbers"].len]["filters"] += list(list("name" = "Fuel", "command" = "fuel_scrub","val" = info["filter_fuel"])) + + var/list/modes = list() + data["mode"] = mode + modes[++modes.len] = list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0) + modes[++modes.len] = list("name" = "Replace Air - Siphons out air while replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 0) + modes[++modes.len] = list("name" = "Panic - Siphons air out of the room", "mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1) + modes[++modes.len] = list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_CYCLE, "selected" = mode == AALARM_MODE_CYCLE, "danger" = 1) + modes[++modes.len] = list("name" = "Fill - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FILL, "selected" = mode == AALARM_MODE_FILL, "danger" = 0) + modes[++modes.len] = list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0) + data["modes"] = modes + + var/list/selected + var/list/thresholds = list() + + var/list/gas_names = list("oxygen", "carbon dioxide", "phoron", "other") + for(var/g in gas_names) + thresholds[++thresholds.len] = list("name" = g, "settings" = list()) + selected = TLV[g] for(var/i = 1, i <= 4, i++) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = i, "selected" = selected[i])) + thresholds[thresholds.len]["settings"] += list(list("env" = g, "val" = i, "selected" = selected[i])) - selected = TLV["temperature"] - thresholds[++thresholds.len] = list("name" = "Temperature", "settings" = list()) - for(var/i = 1, i <= 4, i++) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = i, "selected" = selected[i])) + selected = TLV["pressure"] + thresholds[++thresholds.len] = list("name" = "Pressure", "settings" = list()) + for(var/i = 1, i <= 4, i++) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = i, "selected" = selected[i])) - data["thresholds"] = thresholds + selected = TLV["temperature"] + thresholds[++thresholds.len] = list("name" = "Temperature", "settings" = list()) + for(var/i = 1, i <= 4, i++) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = i, "selected" = selected[i])) -/obj/machinery/alarm/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list = list()) - if(aidisabled && isAI(user)) - to_chat(user, "AI control for \the [src] interface has been disabled.") - return STATUS_CLOSE + data["thresholds"] = thresholds + return data - . = shorted ? STATUS_DISABLED : STATUS_INTERACTIVE +/obj/machinery/alarm/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE - if(. == STATUS_INTERACTIVE) - var/extra_href = state.href_list(usr) - // Prevent remote users from altering RCON settings unless they already have access - if(href_list["rcon"] && extra_href["remote_connection"] && !extra_href["remote_access"]) - . = STATUS_UPDATE - - return min(..(), .) - -/obj/machinery/alarm/Topic(href, href_list, var/datum/topic_state/state) - if(..(href, href_list, state)) - return 1 - - // hrefs that can always be called -walter0o - if(href_list["rcon"]) - var/attempted_rcon_setting = text2num(href_list["rcon"]) + if(action == "rcon") + var/attempted_rcon_setting = text2num(params["rcon"]) switch(attempted_rcon_setting) if(RCON_NO) @@ -631,9 +625,9 @@ rcon_setting = RCON_AUTO if(RCON_YES) rcon_setting = RCON_YES - return 1 + return TRUE - if(href_list["temperature"]) + if(action == "temperature") var/list/selected = TLV["temperature"] var/max_temperature = min(selected[3] - T0C, MAX_TEMPERATURE) var/min_temperature = max(selected[2] - T0C, MIN_TEMPERATURE) @@ -643,119 +637,80 @@ to_chat(usr, "Temperature must be between [min_temperature]C and [max_temperature]C") else target_temperature = input_temperature + T0C - return 1 + return TRUE + + // Account for remote users here. + // Yes, this is kinda snowflaky; however, I would argue it would be far more snowflakey + // to include "custom hrefs" and all the other bullshit that nano states have just for the + // like, two UIs, that want remote access to other UIs. + if((locked && !issilicon(usr) && !istype(state, /datum/tgui_state/air_alarm_remote)) || (issilicon(usr) && aidisabled)) + return - // hrefs that need the AA unlocked -walter0o - var/extra_href = state.href_list(usr) - if(!(locked && !extra_href["remote_connection"]) || extra_href["remote_access"] || issilicon(usr)) - if(href_list["command"]) - var/device_id = href_list["id_tag"] - switch(href_list["command"]) - if("set_external_pressure") - var/input_pressure = input("What pressure you like the system to mantain?", "Pressure Controls") as num|null - if(isnum(input_pressure)) - send_signal(device_id, list(href_list["command"] = input_pressure)) - return 1 + var/device_id = params["id_tag"] + switch(action) + if("lock") + if(issilicon(usr) && !wires.is_cut(WIRE_IDSCAN)) + locked = !locked + . = TRUE + if( "power", + "o2_scrub", + "n2_scrub", + "co2_scrub", + "tox_scrub", + "n2o_scrub", + "fuel_scrub", + "panic_siphon", + "scrubbing", + "direction") + send_signal(device_id, list("[action]" = text2num(params["val"])), usr) + . = TRUE + if("excheck") + send_signal(device_id, list("checks" = text2num(params["val"])^1), usr) + . = TRUE + if("incheck") + send_signal(device_id, list("checks" = text2num(params["val"])^2), usr) + . = TRUE + if("set_external_pressure", "set_internal_pressure") + var/target = params["value"] + if(!isnull(target)) + send_signal(device_id, list("[action]" = target), usr) + . = TRUE + if("reset_external_pressure") + send_signal(device_id, list("reset_external_pressure"), usr) + . = TRUE + if("reset_internal_pressure") + send_signal(device_id, list("reset_internal_pressure"), usr) + . = TRUE + if("threshold") + var/env = params["env"] - if("reset_external_pressure") - send_signal(device_id, list(href_list["command"] = ONE_ATMOSPHERE)) - return 1 - - if( "power", - "adjust_external_pressure", - "checks", - "o2_scrub", - "n2_scrub", - "co2_scrub", - "tox_scrub", - "n2o_scrub", - "fuel_scrub", - "panic_siphon", - "scrubbing", - "direction") - - send_signal(device_id, list(href_list["command"] = text2num(href_list["val"]))) - return 1 - - if("set_threshold") - var/env = href_list["env"] - var/threshold = text2num(href_list["var"]) - var/list/selected = TLV[env] - var/list/thresholds = list("lower bound", "low warning", "high warning", "upper bound") - var/newval = input("Enter [thresholds[threshold]] for [env]", "Alarm triggers", selected[threshold]) as null | num - if(isnull(newval)) - return 1 - if(newval<0) - selected[threshold] = -1.0 - else if(env=="temperature" && newval>5000) - selected[threshold] = 5000 - else if(env=="pressure" && newval>50*ONE_ATMOSPHERE) - selected[threshold] = 50*ONE_ATMOSPHERE - else if(env!="temperature" && env!="pressure" && newval>200) - selected[threshold] = 200 - else - newval = round(newval,0.01) - selected[threshold] = newval - if(threshold == 1) - if(selected[1] > selected[2]) - selected[2] = selected[1] - if(selected[1] > selected[3]) - selected[3] = selected[1] - if(selected[1] > selected[4]) - selected[4] = selected[1] - if(threshold == 2) - if(selected[1] > selected[2]) - selected[1] = selected[2] - if(selected[2] > selected[3]) - selected[3] = selected[2] - if(selected[2] > selected[4]) - selected[4] = selected[2] - if(threshold == 3) - if(selected[1] > selected[3]) - selected[1] = selected[3] - if(selected[2] > selected[3]) - selected[2] = selected[3] - if(selected[3] > selected[4]) - selected[4] = selected[3] - if(threshold == 4) - if(selected[1] > selected[4]) - selected[1] = selected[4] - if(selected[2] > selected[4]) - selected[2] = selected[4] - if(selected[3] > selected[4]) - selected[3] = selected[4] - - apply_mode() - return 1 - - if(href_list["screen"]) - screen = text2num(href_list["screen"]) - return 1 - - if(href_list["atmos_unlock"]) - switch(href_list["atmos_unlock"]) - if("0") - alarm_area.firedoors_close() - if("1") - alarm_area.firedoors_open() - return 1 - - if(href_list["atmos_alarm"]) + var/name = params["var"] + var/value = input("New [name] for [env]:", name, TLV[env][name]) as num|null + if(!isnull(value) && !..()) + if(value < 0) + TLV[env][name] = -1 + else + TLV[env][name] = round(value, 0.01) + // investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS) + . = TRUE + if("mode") + mode = text2num(params["mode"]) + // investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(usr)]",INVESTIGATE_ATMOS) + apply_mode(usr) + . = TRUE + if("alarm") if(alarm_area.atmosalert(2, src)) apply_danger_level(2) - update_icon() - return 1 + . = TRUE + if("reset") + atmos_reset() + . = TRUE + update_icon() - if(href_list["atmos_reset"]) - if(alarm_area.atmosalert(0, src)) - apply_danger_level(0) - update_icon() - return 1 - - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - apply_mode() - return 1 +/obj/machinery/alarm/proc/atmos_reset() + if(alarm_area.atmosalert(0, src)) + apply_danger_level(0) + update_icon() /obj/machinery/alarm/attackby(obj/item/W as obj, mob/user as mob) add_fingerprint(user) diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm index 5ebcfeef43..2d87fcd45a 100644 --- a/code/game/machinery/atmo_control.dm +++ b/code/game/machinery/atmo_control.dm @@ -94,7 +94,7 @@ obj/machinery/computer/general_air_control/Destroy() if(..(user)) return - ui_interact(user) + tgui_interact(user) /obj/machinery/computer/general_air_control/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -104,9 +104,13 @@ obj/machinery/computer/general_air_control/Destroy() sensor_information[id_tag] = signal.data -/obj/machinery/computer/general_air_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/general_air_control/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GeneralAtmoControl", name) + ui.open() +/obj/machinery/computer/general_air_control/tgui_data(mob/user) var/list/data = list() var/sensors_ui[0] if(sensors.len) @@ -119,12 +123,7 @@ obj/machinery/computer/general_air_control/Destroy() data["sensors"] = sensors_ui - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmo_control.tmpl", name, 525, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data /obj/machinery/computer/general_air_control/proc/set_frequency(new_frequency) radio_controller.remove_object(src, frequency) @@ -147,20 +146,9 @@ obj/machinery/computer/general_air_control/Destroy() var/pressure_setting = ONE_ATMOSPHERE * 45 circuit = /obj/item/weapon/circuitboard/air_management/tank_control -/obj/machinery/computer/general_air_control/large_tank_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/general_air_control/large_tank_control/tgui_data(mob/user) + var/list/data = ..() - var/list/data = list() - var/sensors_ui[0] - if(sensors.len) - for(var/id_tag in sensors) - var/long_name = sensors[id_tag] - var/list/sensor_data = sensor_information[id_tag] - sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) - else - sensors_ui = null - - data["sensors"] = sensors_ui data["tanks"] = 1 if(input_info) @@ -175,13 +163,10 @@ obj/machinery/computer/general_air_control/Destroy() data["input_flow_setting"] = round(input_flow_setting, 0.1) data["pressure_setting"] = pressure_setting + data["max_pressure"] = 50*ONE_ATMOSPHERE + data["max_flowrate"] = ATMOS_DEFAULT_VOLUME_PUMP + 500 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmo_control.tmpl", name, 660, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data /obj/machinery/computer/general_air_control/large_tank_control/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -195,54 +180,56 @@ obj/machinery/computer/general_air_control/Destroy() else ..(signal) -/obj/machinery/computer/general_air_control/large_tank_control/Topic(href, href_list) +/obj/machinery/computer/general_air_control/large_tank_control/tgui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["adj_pressure"]) - var/change = text2num(href_list["adj_pressure"]) - pressure_setting = between(0, pressure_setting + change, 50*ONE_ATMOSPHERE) - return 1 + switch(action) + if("adj_pressure") + var/new_pressure = text2num(params["adj_pressure"]) + pressure_setting = between(0, new_pressure, 50*ONE_ATMOSPHERE) + return TRUE - if(href_list["adj_input_flow_rate"]) - var/change = text2num(href_list["adj_input_flow_rate"]) - input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors - return 1 + if("adj_input_flow_rate") + var/new_flow = text2num(params["adj_input_flow_rate"]) + input_flow_setting = between(0, new_flow, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors + return TRUE if(!radio_connection) - return 0 + return FALSE var/datum/signal/signal = new signal.transmission_method = TRANSMISSION_RADIO //radio signal signal.source = src - if(href_list["in_refresh_status"]) - input_info = null - signal.data = list ("tag" = input_tag, "status" = 1) - . = 1 + switch(action) + if("in_refresh_status") + input_info = null + signal.data = list ("tag" = input_tag, "status" = 1) + . = TRUE - if(href_list["in_toggle_injector"]) - input_info = null - signal.data = list ("tag" = input_tag, "power_toggle" = 1) - . = 1 + if("in_toggle_injector") + input_info = null + signal.data = list ("tag" = input_tag, "power_toggle" = 1) + . = TRUE - if(href_list["in_set_flowrate"]) - input_info = null - signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") - . = 1 + if("in_set_flowrate") + input_info = null + signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") + . = TRUE - if(href_list["out_refresh_status"]) - output_info = null - signal.data = list ("tag" = output_tag, "status" = 1) - . = 1 + if("out_refresh_status") + output_info = null + signal.data = list ("tag" = output_tag, "status" = 1) + . = TRUE - if(href_list["out_toggle_power"]) - output_info = null - signal.data = list ("tag" = output_tag, "power_toggle" = 1) - . = 1 + if("out_toggle_power") + output_info = null + signal.data = list ("tag" = output_tag, "power_toggle" = 1) + . = TRUE - if(href_list["out_set_pressure"]) - output_info = null - signal.data = list ("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]") - . = 1 + if("out_set_pressure") + output_info = null + signal.data = list ("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]") + . = TRUE signal.data["sigtype"]="command" radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) @@ -258,40 +245,29 @@ obj/machinery/computer/general_air_control/Destroy() var/pressure_setting = 100 circuit = /obj/item/weapon/circuitboard/air_management/supermatter_core -/obj/machinery/computer/general_air_control/supermatter_core/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - var/list/data = list() - var/sensors_ui[0] - if(sensors.len) - for(var/id_tag in sensors) - var/long_name = sensors[id_tag] - var/list/sensor_data = sensor_information[id_tag] - sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) - else - sensors_ui = null - - data["sensors"] = sensors_ui +/obj/machinery/computer/general_air_control/supermatter_core/tgui_data(mob/user) + var/list/data = ..() data["core"] = 1 if(input_info) data["input_info"] = list("power" = input_info["power"], "volume_rate" = round(input_info["volume_rate"], 0.1)) else data["input_info"] = null + if(output_info) - data["output_info"] = list("power" = output_info["power"], "pressure_limit" = output_info["external"]) + // Yes, TECHNICALLY this is not output pressure, it's a pressure LIMIT. HOWEVER. The fact that the UI uses "output_pressure" + // in EXACTLY THE SAME WAY as "pressure_limit" means this should just pass it as the other fucking data argument because holy shit what the + // fuck + data["output_info"] = list("power" = output_info["power"], "output_pressure" = output_info["external"]) else data["output_info"] = null data["input_flow_setting"] = round(input_flow_setting, 0.1) data["pressure_setting"] = pressure_setting + data["max_pressure"] = 10*ONE_ATMOSPHERE + data["max_flowrate"] = ATMOS_DEFAULT_VOLUME_PUMP + 500 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmo_control.tmpl", name, 650, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data /obj/machinery/computer/general_air_control/supermatter_core/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -305,54 +281,56 @@ obj/machinery/computer/general_air_control/Destroy() else ..(signal) -/obj/machinery/computer/general_air_control/supermatter_core/Topic(href, href_list) +/obj/machinery/computer/general_air_control/supermatter_core/tgui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["adj_pressure"]) - var/change = text2num(href_list["adj_pressure"]) - pressure_setting = between(0, pressure_setting + change, 10*ONE_ATMOSPHERE) - return 1 + switch(action) + if("adj_pressure") + var/new_pressure = text2num(params["adj_pressure"]) + pressure_setting = between(0, new_pressure, 10*ONE_ATMOSPHERE) + return TRUE - if(href_list["adj_input_flow_rate"]) - var/change = text2num(href_list["adj_input_flow_rate"]) - input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors - return 1 + if("adj_input_flow_rate") + var/new_flow = text2num(params["adj_input_flow_rate"]) + input_flow_setting = between(0, new_flow, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors + return TRUE if(!radio_connection) - return 0 + return FALSE var/datum/signal/signal = new signal.transmission_method = TRANSMISSION_RADIO //radio signal signal.source = src - if(href_list["in_refresh_status"]) - input_info = null - signal.data = list ("tag" = input_tag, "status" = 1) - . = 1 + switch(action) + if("in_refresh_status") + input_info = null + signal.data = list ("tag" = input_tag, "status" = 1) + . = TRUE - if(href_list["in_toggle_injector"]) - input_info = null - signal.data = list ("tag" = input_tag, "power_toggle" = 1) - . = 1 + if("in_toggle_injector") + input_info = null + signal.data = list ("tag" = input_tag, "power_toggle" = 1) + . = TRUE - if(href_list["in_set_flowrate"]) - input_info = null - signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") - . = 1 + if("in_set_flowrate") + input_info = null + signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") + . = TRUE - if(href_list["out_refresh_status"]) - output_info = null - signal.data = list ("tag" = output_tag, "status" = 1) - . = 1 + if("out_refresh_status") + output_info = null + signal.data = list ("tag" = output_tag, "status" = 1) + . = TRUE - if(href_list["out_toggle_power"]) - output_info = null - signal.data = list ("tag" = output_tag, "power_toggle" = 1) - . = 1 + if("out_toggle_power") + output_info = null + signal.data = list ("tag" = output_tag, "power_toggle" = 1) + . = TRUE - if(href_list["out_set_pressure"]) - output_info = null - signal.data = list ("tag" = output_tag, "set_external_pressure" = "[pressure_setting]", "checks" = 1) - . = 1 + if("out_set_pressure") + output_info = null + signal.data = list ("tag" = output_tag, "set_external_pressure" = "[pressure_setting]", "checks" = 1) + . = TRUE signal.data["sigtype"]="command" radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) @@ -370,7 +348,7 @@ obj/machinery/computer/general_air_control/Destroy() /obj/machinery/computer/general_air_control/fuel_injection/process() if(automation) if(!radio_connection) - return 0 + return FALSE var/injecting = 0 for(var/id_tag in sensor_information) @@ -396,20 +374,8 @@ obj/machinery/computer/general_air_control/Destroy() ..() -/obj/machinery/computer/general_air_control/fuel_injection/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - var/list/data = list() - var/sensors_ui[0] - if(sensors.len) - for(var/id_tag in sensors) - var/long_name = sensors[id_tag] - var/list/sensor_data = sensor_information[id_tag] - sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) - else - sensors_ui = null - - data["sensors"] = sensors_ui +/obj/machinery/computer/general_air_control/fuel_injection/tgui_data(mob/user) + var/list/data = ..() data["fuel"] = 1 data["automation"] = automation @@ -418,12 +384,7 @@ obj/machinery/computer/general_air_control/Destroy() else data["device_info"] = null - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmo_control.tmpl", name, 650, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data /obj/machinery/computer/general_air_control/fuel_injection/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -435,55 +396,60 @@ obj/machinery/computer/general_air_control/Destroy() else ..(signal) -/obj/machinery/computer/general_air_control/fuel_injection/Topic(href, href_list) +/obj/machinery/computer/general_air_control/fuel_injection/tgui_act(action, params) if(..()) - return + return TRUE + + switch(action) + if("refresh_status") + device_info = null + if(!radio_connection) + return FALSE - if(href_list["refresh_status"]) - device_info = null - if(!radio_connection) - return 0 + var/datum/signal/signal = new + signal.transmission_method = TRANSMISSION_RADIO //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "status" = 1, + "sigtype"="command" + ) + radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + . = TRUE - var/datum/signal/signal = new - signal.transmission_method = TRANSMISSION_RADIO //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "status" = 1, - "sigtype"="command" - ) - radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + if("toggle_automation") + automation = !automation + . = TRUE - if(href_list["toggle_automation"]) - automation = !automation + if("toggle_injector") + device_info = null + if(!radio_connection) + return FALSE - if(href_list["toggle_injector"]) - device_info = null - if(!radio_connection) - return 0 + var/datum/signal/signal = new + signal.transmission_method = TRANSMISSION_RADIO //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "power_toggle" = 1, + "sigtype"="command" + ) - var/datum/signal/signal = new - signal.transmission_method = TRANSMISSION_RADIO //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "power_toggle" = 1, - "sigtype"="command" - ) + radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + . = TRUE - radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + if("injection") + if(!radio_connection) + return FALSE - if(href_list["injection"]) - if(!radio_connection) - return 0 + var/datum/signal/signal = new + signal.transmission_method = TRANSMISSION_RADIO //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "inject" = 1, + "sigtype"="command" + ) - var/datum/signal/signal = new - signal.transmission_method = TRANSMISSION_RADIO //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "inject" = 1, - "sigtype"="command" - ) - - radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) \ No newline at end of file + radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + . = TRUE \ No newline at end of file diff --git a/code/game/machinery/atmoalter/area_atmos_computer.dm b/code/game/machinery/atmoalter/area_atmos_computer.dm index 125b55eb7f..55523ed079 100644 --- a/code/game/machinery/atmoalter/area_atmos_computer.dm +++ b/code/game/machinery/atmoalter/area_atmos_computer.dm @@ -24,94 +24,70 @@ /obj/machinery/computer/area_atmos/attack_hand(var/mob/user as mob) if(..(user)) return - src.add_fingerprint(usr) - var/dat = {" - - - - - -

Area Air Control

- [status]
- Scan - "} - for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in connectedscrubbers) - dat += {" - - - - "} + tgui_interact(user) - dat += {" -
- [scrubber.name]
- Pressure: [round(scrubber.air_contents.return_pressure(), 0.01)] kPa
- Flow Rate: [round(scrubber.last_flow_rate,0.1)] L/s
-
- Turn On - Turn Off
- Load: [round(scrubber.last_power_draw)] W -

- [zone] - - "} - user << browse("[dat]", "window=miningshuttle;size=400x400") - status = "" - -/obj/machinery/computer/area_atmos/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) - - - if(href_list["scan"]) - scanscrubbers() - else if(href_list["toggle"]) - var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber = locate(href_list["scrub"]) +/obj/machinery/computer/area_atmos/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AreaScrubberControl", name) + ui.open() +/obj/machinery/computer/area_atmos/tgui_data(mob/user) + var/list/data = list() + + data["scrubbers"] = list() + for(var/id in connectedscrubbers) + var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber = connectedscrubbers[id] if(!validscrubber(scrubber)) - spawn(20) - status = "ERROR: Couldn't connect to scrubber! (timeout)" - connectedscrubbers -= scrubber - src.updateUsrDialog() - return + connectedscrubbers -= scrubber + continue + data["scrubbers"].Add(list(list( + "id" = id, + "name" = scrubber.name, + "on" = scrubber.on, + "pressure" = scrubber.air_contents.return_pressure(), + "flow_rate" = scrubber.last_flow_rate, + "load" = scrubber.last_power_draw, + "area" = get_area(scrubber), + ))) - scrubber.on = text2num(href_list["toggle"]) - scrubber.update_icon() + return data + +/obj/machinery/computer/area_atmos/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("toggle") + var/scrub_id = params["id"] + var/obj/machinery/portable_atmospherics/powered/scrubber/huge/S = connectedscrubbers["[scrub_id]"] + if(!validscrubber(S)) + connectedscrubbers -= S + return TRUE + S.on = !S.on + S.update_icon() + . = TRUE + if("allon") + INVOKE_ASYNC(src, .proc/toggle_all, TRUE) + . = TRUE + if("alloff") + INVOKE_ASYNC(src, .proc/toggle_all, FALSE) + . = TRUE + if("scan") + scanscrubbers() + . = TRUE + + add_fingerprint(usr) + +/obj/machinery/computer/area_atmos/proc/toggle_all(on) + for(var/id in connectedscrubbers) + var/obj/machinery/portable_atmospherics/powered/scrubber/huge/S = connectedscrubbers["[id]"] + if(!validscrubber(S)) + connectedscrubbers -= S + continue + S.on = on + S.update_icon() + CHECK_TICK /obj/machinery/computer/area_atmos/proc/validscrubber(obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber as obj) if(!isobj(scrubber) || get_dist(scrubber.loc, src.loc) > src.range || scrubber.loc.z != src.loc.z) @@ -119,13 +95,12 @@ return TRUE /obj/machinery/computer/area_atmos/proc/scanscrubbers() - connectedscrubbers = new() + connectedscrubbers = list() var/found = 0 for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in range(range, src.loc)) - if(istype(scrubber)) - found = 1 - connectedscrubbers += scrubber + found = 1 + connectedscrubbers["[scrubber.id]"] = scrubber if(!found) status = "ERROR: No scrubber found!" @@ -142,7 +117,7 @@ var/found = 0 var/area/A = get_area(src) for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in A) - connectedscrubbers += scrubber + connectedscrubbers["[scrubber.id]"] = scrubber found = 1 if(!found) @@ -151,7 +126,10 @@ src.updateUsrDialog() /obj/machinery/computer/area_atmos/area/validscrubber(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) - if(get_area(scrubber) == get_area(src)) - return 1 + if(!istype(scrubber)) + return FALSE - return 0 + if(get_area(scrubber) == get_area(src)) + return TRUE + + return FALSE diff --git a/code/game/machinery/atmoalter/area_atmos_computer_vr.dm b/code/game/machinery/atmoalter/area_atmos_computer_vr.dm index e489bb39fb..e20e8e1b71 100644 --- a/code/game/machinery/atmoalter/area_atmos_computer_vr.dm +++ b/code/game/machinery/atmoalter/area_atmos_computer_vr.dm @@ -17,12 +17,15 @@ for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in world) if(scrubber.scrub_id == src.scrub_id) - connectedscrubbers += scrubber + connectedscrubbers["[scrubber.id]"] = scrubber - src.updateUsrDialog() + SStgui.update_uis(src) /obj/machinery/computer/area_atmos/tag/validscrubber(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) + if(!istype(scrubber)) + return FALSE + if(scrubber.scrub_id == src.scrub_id) - return 1 + return TRUE - return 0 + return FALSE \ No newline at end of file diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 3a012a1ccd..7faf1115fe 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -266,105 +266,108 @@ update_flag return src.attack_hand(user) /obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user as mob) - return src.ui_interact(user) + return tgui_interact(user) -/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if (src.destroyed) +/obj/machinery/portable_atmospherics/canister/tgui_state(mob/user) + return GLOB.tgui_physical_state + +/obj/machinery/portable_atmospherics/canister/tgui_interact(mob/user, datum/tgui/ui) + if(destroyed) return + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Canister", name) + ui.open() - // this is the data which will be sent to the ui - var/data[0] - data["name"] = name +/obj/machinery/portable_atmospherics/canister/tgui_data(mob/user) + var/list/data = list() data["canLabel"] = can_label ? 1 : 0 - data["portConnected"] = connected_port ? 1 : 0 - data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) + data["connected"] = connected_port ? 1 : 0 + data["pressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) data["releasePressure"] = round(release_pressure ? release_pressure : 0) + data["defaultReleasePressure"] = round(initial(release_pressure)) data["minReleasePressure"] = round(ONE_ATMOSPHERE/10) data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE) data["valveOpen"] = valve_open ? 1 : 0 - data["hasHoldingTank"] = holding ? 1 : 0 - if (holding) - data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure())) + if(holding) + data["holding"] = list() + data["holding"]["name"] = holding.name + data["holding"]["pressure"] = round(holding.air_contents.return_pressure()) + else + data["holding"] = null - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "canister.tmpl", "Canister", 480, 400) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + return data -/obj/machinery/portable_atmospherics/canister/Topic(href, href_list) +/obj/machinery/portable_atmospherics/canister/tgui_act(action, params) + if(..()) + return TRUE - //Do not use "if(..()) return" here, canisters will stop working in unpowered areas like space or on the derelict. // yeah but without SOME sort of Topic check any dick can mess with them via exploits as he pleases -walter0o - //First comment might be outdated. - if (!istype(src.loc, /turf)) - return 0 - - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) // exploit protection -walter0o - usr << browse(null, "window=canister") - onclose(usr, "canister") - return - - if(href_list["toggle"]) - if (valve_open) - if (holding) - release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" + switch(action) + if("relabel") + if(can_label) + var/list/colors = list(\ + "\[N2O\]" = "redws", \ + "\[N2\]" = "red", \ + "\[O2\]" = "blue", \ + "\[Phoron\]" = "orangeps", \ + "\[CO2\]" = "black", \ + "\[Air\]" = "grey", \ + "\[CAUTION\]" = "yellow", \ + ) + var/label = input("Choose canister label", "Gas canister") as null|anything in colors + if(label) + canister_color = colors[label] + icon_state = colors[label] + name = "Canister: [label]" + if("pressure") + var/pressure = params["pressure"] + if(pressure == "reset") + pressure = initial(release_pressure) + . = TRUE + else if(pressure == "min") + pressure = ONE_ATMOSPHERE/10 + . = TRUE + else if(pressure == "max") + pressure = 10*ONE_ATMOSPHERE + . = TRUE + else if(pressure == "input") + pressure = input("New release pressure ([ONE_ATMOSPHERE/10]-[10*ONE_ATMOSPHERE] kPa):", name, release_pressure) as num|null + if(!isnull(pressure) && !..()) + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + release_pressure = clamp(round(pressure), ONE_ATMOSPHERE/10, 10*ONE_ATMOSPHERE) + if("valve") + if(valve_open) + if(holding) + release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" + else + release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
" else - release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
" - else - if (holding) - release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the [holding]
" - else - release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
" - log_open() - valve_open = !valve_open + if(holding) + release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the [holding]
" + else + release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
" + log_open() + valve_open = !valve_open + . = TRUE + if("eject") + if(holding) + if(valve_open) + valve_open = 0 + release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" + if(istype(holding, /obj/item/weapon/tank)) + holding.manipulated_by = usr.real_name + holding.loc = loc + holding = null + . = TRUE - if (href_list["remove_tank"]) - if(holding) - if (valve_open) - valve_open = 0 - release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" - if(istype(holding, /obj/item/weapon/tank)) - holding.manipulated_by = usr.real_name - holding.loc = loc - holding = null - - if (href_list["pressure_adj"]) - var/diff = text2num(href_list["pressure_adj"]) - if(diff > 0) - release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff) - else - release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff) - - if (href_list["relabel"]) - if (can_label) - var/list/colors = list(\ - "\[N2O\]" = "redws", \ - "\[N2\]" = "red", \ - "\[O2\]" = "blue", \ - "\[Phoron\]" = "orangeps", \ - "\[CO2\]" = "black", \ - "\[Air\]" = "grey", \ - "\[CAUTION\]" = "yellow", \ - ) - var/label = input("Choose canister label", "Gas canister") as null|anything in colors - if (label) - src.canister_color = colors[label] - src.icon_state = colors[label] - src.name = "Canister: [label]" - - src.add_fingerprint(usr) + add_fingerprint(usr) update_icon() - return 1 - /obj/machinery/portable_atmospherics/canister/phoron/New() ..() diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm index 758c2a57cb..74e4804661 100644 --- a/code/game/machinery/atmoalter/pump.dm +++ b/code/game/machinery/atmoalter/pump.dm @@ -119,51 +119,73 @@ return src.attack_hand(user) /obj/machinery/portable_atmospherics/powered/pump/attack_hand(var/mob/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/portable_atmospherics/powered/pump/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) +/obj/machinery/portable_atmospherics/powered/pump/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortablePump", name) + ui.open() + + +/obj/machinery/portable_atmospherics/powered/pump/tgui_state(mob/user) + return GLOB.tgui_physical_state + +/obj/machinery/portable_atmospherics/powered/pump/tgui_data(mob/user) var/list/data[0] - data["portConnected"] = connected_port ? 1 : 0 - data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) - data["targetpressure"] = round(target_pressure) - data["pump_dir"] = direction_out - data["minpressure"] = round(pressuremin) - data["maxpressure"] = round(pressuremax) + data["on"] = on ? TRUE : FALSE + data["direction"] = !direction_out ? TRUE : FALSE + data["connected"] = connected_port ? TRUE : FALSE + data["pressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) + data["target_pressure"] = round(target_pressure ? target_pressure : 0) + data["default_pressure"] = round(initial(target_pressure)) + data["min_pressure"] = round(pressuremin) + data["max_pressure"] = round(pressuremax) + data["powerDraw"] = round(last_power_draw) data["cellCharge"] = cell ? cell.charge : 0 data["cellMaxCharge"] = cell ? cell.maxcharge : 1 - data["on"] = on ? 1 : 0 - data["hasHoldingTank"] = holding ? 1 : 0 - if (holding) - data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0)) + if(holding) + data["holding"] = list() + data["holding"]["name"] = holding.name + data["holding"]["pressure"] = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0) + else + data["holding"] = null + + return data - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "portpump.tmpl", "Portable Pump", 480, 410, state = physical_state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/portable_atmospherics/powered/pump/Topic(href, href_list) +/obj/machinery/portable_atmospherics/powered/pump/tgui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["power"]) - on = !on - . = 1 - if(href_list["direction"]) - direction_out = !direction_out - . = 1 - if (href_list["remove_tank"]) - if(holding) - holding.loc = loc - holding = null - . = 1 - if (href_list["pressure_adj"]) - var/diff = text2num(href_list["pressure_adj"]) - target_pressure = min(10*ONE_ATMOSPHERE, max(0, target_pressure+diff)) - . = 1 + switch(action) + if("power") + on = !on + . = 1 + if("direction") + direction_out = !direction_out + . = 1 + if("eject") + if(holding) + holding.loc = loc + holding = null + . = 1 + if("pressure") + var/pressure = params["pressure"] + if(pressure == "reset") + pressure = initial(target_pressure) + . = TRUE + else if(pressure == "min") + pressure = pressuremin + . = TRUE + else if(pressure == "max") + pressure = pressuremax + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + target_pressure = clamp(round(pressure), pressuremin, pressuremax) - if(.) - update_icon() + update_icon() diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm index 219cf7801f..b6e4c0e124 100644 --- a/code/game/machinery/atmoalter/scrubber.dm +++ b/code/game/machinery/atmoalter/scrubber.dm @@ -96,49 +96,53 @@ return src.attack_hand(user) /obj/machinery/portable_atmospherics/powered/scrubber/attack_hand(var/mob/user) - ui_interact(user) - return + tgui_interact(user) -/obj/machinery/portable_atmospherics/powered/scrubber/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) - var/list/data[0] - data["portConnected"] = connected_port ? 1 : 0 - data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) +/obj/machinery/portable_atmospherics/powered/scrubber/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortableScrubber", name) + ui.open() + +/obj/machinery/portable_atmospherics/powered/scrubber/tgui_data(mob/user) + var/list/data = list() + data["on"] = on ? 1 : 0 + data["connected"] = connected_port ? 1 : 0 + data["pressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) + data["rate"] = round(volume_rate) data["minrate"] = round(minrate) data["maxrate"] = round(maxrate) data["powerDraw"] = round(last_power_draw) data["cellCharge"] = cell ? cell.charge : 0 data["cellMaxCharge"] = cell ? cell.maxcharge : 1 - data["on"] = on ? 1 : 0 - data["hasHoldingTank"] = holding ? 1 : 0 - if (holding) - data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0)) + if(holding) + data["holding"] = list() + data["holding"]["name"] = holding.name + data["holding"]["pressure"] = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0) + else + data["holding"] = null - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "portscrubber.tmpl", "Portable Scrubber", 480, 400, state = physical_state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data - -/obj/machinery/portable_atmospherics/powered/scrubber/Topic(href, href_list) +/obj/machinery/portable_atmospherics/powered/scrubber/tgui_act(action, params) if(..()) - return 1 + return TRUE + + switch(action) + if("power") + on = !on + . = TRUE + if("eject") + if(holding) + holding.loc = loc + holding = null + . = TRUE + if("volume_adj") + volume_rate = CLAMP(text2num(params["vol"]), minrate, maxrate) + . = TRUE - if(href_list["power"]) - on = !on - . = 1 - if (href_list["remove_tank"]) - if(holding) - holding.loc = loc - holding = null - . = 1 - if (href_list["volume_adj"]) - var/diff = text2num(href_list["volume_adj"]) - volume_rate = CLAMP(volume_rate+diff, minrate, maxrate) - . = 1 update_icon() diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 4bd203d0ba..73b78cb148 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -447,7 +447,7 @@ network.Cut() update_coverage(1) -/obj/machinery/camera/proc/nano_structure() +/obj/machinery/camera/proc/tgui_structure() var/cam[0] cam["name"] = sanitize(c_tag) cam["deact"] = !can_use() diff --git a/code/game/machinery/computer/RCON_Console.dm b/code/game/machinery/computer/RCON_Console.dm index fbd1190fd7..d6df0d2d6d 100644 --- a/code/game/machinery/computer/RCON_Console.dm +++ b/code/game/machinery/computer/RCON_Console.dm @@ -13,7 +13,7 @@ circuit = /obj/item/weapon/circuitboard/rcon_console req_one_access = list(access_engine) var/current_tag = null - var/datum/nano_module/rcon/rcon + var/datum/tgui_module/rcon/rcon /obj/machinery/computer/rcon/New() ..() @@ -29,13 +29,12 @@ // Description: Opens UI of this machine. /obj/machinery/computer/rcon/attack_hand(var/mob/user as mob) ..() - ui_interact(user) + tgui_interact(user) // Proc: ui_interact() -// Parameters: 4 (standard NanoUI parameters) -// Description: Uses dark magic (NanoUI) to render this machine's UI -/obj/machinery/computer/rcon/ui_interact(mob/user, ui_key = "rcon", var/datum/nanoui/ui = null, var/force_open = 1) - rcon.ui_interact(user, ui_key, ui, force_open) +// Description: Uses dark magic (TGUI) to render this machine's UI +/obj/machinery/computer/rcon/tgui_interact(mob/user, datum/tgui/ui) + rcon.tgui_interact(user, ui) /obj/machinery/computer/rcon/update_icon() ..() diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm index f83a87c266..3ec9e2c841 100644 --- a/code/game/machinery/computer/aifixer.dm +++ b/code/game/machinery/computer/aifixer.dm @@ -82,7 +82,7 @@ /obj/machinery/computer/aifixer/tgui_act(action, params) if(..()) - return + return TRUE if(!occupier) restoring = FALSE diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index 7f5c27a0d4..304c254837 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -17,16 +17,22 @@ var/global/list/minor_air_alarms = list() atmosphere_alarm.register_alarm(src, /obj/machinery/computer/station_alert/update_icon) /obj/machinery/computer/atmos_alert/Destroy() - atmosphere_alarm.unregister_alarm(src) - ..() + atmosphere_alarm.unregister_alarm(src) + ..() /obj/machinery/computer/atmos_alert/attack_hand(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/atmos_alert/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - var/major_alarms[0] - var/minor_alarms[0] +/obj/machinery/computer/atmos_alert/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AtmosAlertConsole", name) + ui.open() + +/obj/machinery/computer/atmos_alert/tgui_data(mob/user) + var/list/data = list() + var/list/major_alarms = list() + var/list/minor_alarms = list() for(var/datum/alarm/alarm in atmosphere_alarm.major_alarms(get_z(src))) major_alarms[++major_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]") @@ -37,12 +43,7 @@ var/global/list/minor_air_alarms = list() data["priority_alarms"] = major_alarms data["minor_alarms"] = minor_alarms - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmos_alert.tmpl", src.name, 500, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data /obj/machinery/computer/atmos_alert/update_icon() if(!(stat & (NOPOWER|BROKEN))) @@ -57,26 +58,21 @@ var/global/list/minor_air_alarms = list() icon_screen = initial(icon_screen) ..() -/obj/machinery/computer/atmos_alert/Topic(href, href_list) +/obj/machinery/computer/atmos_alert/tgui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["clear_alarm"]) - var/datum/alarm/alarm = locate(href_list["clear_alarm"]) in atmosphere_alarm.alarms - if(alarm) - for(var/datum/alarm_source/alarm_source in alarm.sources) - var/obj/machinery/alarm/air_alarm = alarm_source.source - if(istype(air_alarm)) - var/list/new_ref = list("atmos_reset" = 1) - air_alarm.Topic(href, new_ref, state = air_alarm_topic) - return 1 - - -var/datum/topic_state/air_alarm_topic/air_alarm_topic = new() - -/datum/topic_state/air_alarm_topic/href_list(var/mob/user) - var/list/extra_href = list() - extra_href["remote_connection"] = 1 - extra_href["remote_access"] = 1 - - return extra_href + switch(action) + if("clear") + var/datum/alarm/alarm = locate(params["ref"]) in atmosphere_alarm.alarms + if(alarm) + for(var/datum/alarm_source/alarm_source in alarm.sources) + var/obj/machinery/alarm/air_alarm = alarm_source.source + if(istype(air_alarm)) + // I have to leave a note here: + // Once upon a time, this called air_alarm.Topic() with a custom topic state + // in order to perform three lines of code. In other words, pure insanity. + // Whyyyyyyyyyyyyyyyyyyyyyyy. + air_alarm.atmos_reset() + . = TRUE + update_icon() diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm index 48f899ed0d..c38af8ae41 100644 --- a/code/game/machinery/computer/atmos_control.dm +++ b/code/game/machinery/computer/atmos_control.dm @@ -13,7 +13,7 @@ circuit = /obj/item/weapon/circuitboard/atmoscontrol req_access = list(access_ce) var/list/monitored_alarm_ids = null - var/datum/nano_module/atmos_control/atmos_control + var/datum/tgui_module/atmos_control/atmos_control /obj/machinery/computer/atmoscontrol/New() ..() @@ -27,12 +27,12 @@ density = 0 /obj/machinery/computer/atmoscontrol/attack_ai(var/mob/user as mob) - ui_interact(user) + tgui_interact(user) /obj/machinery/computer/atmoscontrol/attack_hand(mob/user) if(..()) return 1 - ui_interact(user) + tgui_interact(user) /obj/machinery/computer/atmoscontrol/emag_act(var/remaining_carges, var/mob/user) if(!emagged) @@ -42,7 +42,7 @@ atmos_control.emagged = 1 return 1 -/obj/machinery/computer/atmoscontrol/ui_interact(var/mob/user) +/obj/machinery/computer/atmoscontrol/tgui_interact(var/mob/user) if(!atmos_control) atmos_control = new(src, req_access, req_one_access, monitored_alarm_ids) - atmos_control.ui_interact(user) + atmos_control.tgui_interact(user) diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm index 2416a0cd35..1dc0709ed3 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -12,23 +12,21 @@ //Sparks effect - For emag var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread //Messages - Saves me time if I want to change something. - var/noserver = "ALERT: No server detected." - var/incorrectkey = "ALERT: Incorrect decryption key!" - var/defaultmsg = "Welcome. Please select an option." - var/rebootmsg = "%$&(£: Critical %$$@ Error // !RestArting! - ?pLeaSe wAit!" + var/noserver = list("text" = "ALERT: No server detected.", "style" = "alert") + var/incorrectkey = list("text" = "ALERT: Incorrect decryption key!", "style" = "warning") + var/defaultmsg = list("text" = "Welcome. Please select an option.", "style" = "notice") + var/rebootmsg = list("text" = "%$&(£: Critical %$$@ Error // !RestArting! - ?pLeaSe wAit!", "style" = "warning") //Computer properties - var/screen = 0 // 0 = Main menu, 1 = Message Logs, 2 = Hacked screen, 3 = Custom Message var/hacking = 0 // Is it being hacked into by the AI/Cyborg var/emag = 0 // When it is emagged. - var/message = "System bootup complete. Please select an option." // The message that shows on the main menu. var/auth = 0 // Are they authenticated? var/optioncount = 8 - // Custom Message Properties + // Custom temp Properties var/customsender = "System Administrator" var/obj/item/device/pda/customrecepient = null var/customjob = "Admin" var/custommessage = "This is a test, please ignore." - + var/list/temp = null /obj/machinery/computer/message_monitor/attackby(obj/item/weapon/O as obj, mob/living/user as mob) if(stat & (NOPOWER|BROKEN)) @@ -48,17 +46,16 @@ // Will create sparks and print out the console's password. You will then have to wait a while for the console to be back online. // It'll take more time if there's more characters in the password.. if(!emag && operable()) - if(!isnull(src.linkedServer)) + if(!isnull(linkedServer)) emag = 1 - screen = 2 spark_system.set_up(5, 0, src) - src.spark_system.start() + spark_system.start() var/obj/item/weapon/paper/monitorkey/MK = new/obj/item/weapon/paper/monitorkey - MK.loc = src.loc + MK.loc = loc // Will help make emagging the console not so easy to get away with. MK.info += "

£%@%(*$%&(£&?*(%&£/{}" - spawn(100*length(src.linkedServer.decryptkey)) UnmagConsole() - message = rebootmsg + spawn(100*length(linkedServer.decryptkey)) UnmagConsole() + temp = rebootmsg update_icon() return 1 else @@ -78,201 +75,92 @@ linkedServer = message_servers[1] return ..() +/obj/machinery/computer/message_monitor/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "MessageMonitor", name) + ui.open() + +/obj/machinery/computer/message_monitor/tgui_data(mob/user) + var/list/data = list() + + data["customsender"] = customsender + data["customrecepient"] = "[customrecepient]" + data["customjob"] = customjob + data["custommessage"] = custommessage + + data["temp"] = temp + data["hacking"] = !!hacking + data["emag"] = !!emag + data["auth"] = !!auth + data["linkedServer"] = list() + if(linkedServer && auth) + data["linkedServer"]["active"] = linkedServer.active + data["linkedServer"]["broke"] = linkedServer.stat & (NOPOWER|BROKEN) + + data["linkedServer"]["pda_msgs"] = list() + for(var/datum/data_pda_msg/pda in linkedServer.pda_msgs) + data["linkedServer"]["pda_msgs"].Add(list(list( + "ref" = "\ref[pda]", + "sender" = pda.sender, + "recipient" = pda.recipient, + "message" = pda.message, + ))) + + data["linkedServer"]["rc_msgs"] = list() + for(var/datum/data_rc_msg/rc in linkedServer.rc_msgs) + data["linkedServer"]["rc_msgs"].Add(list(list( + "ref" = "\ref[rc]", + "sender" = rc.send_dpt, + "recipient" = rc.rec_dpt, + "message" = rc.message, + "stamp" = rc.stamp, + "id_auth" = rc.id_auth, + "priority" = rc.priority, + ))) + + var/spamIndex = 0 + data["linkedServer"]["spamFilter"] = list() + for(var/token in linkedServer.spamfilter) + spamIndex++ + data["linkedServer"]["spamFilter"].Add(list(list( + "index" = spamIndex, + "token" = token, + ))) + + //Get out list of viable PDAs + var/list/obj/item/device/pda/sendPDAs = list() + for(var/obj/item/device/pda/P in PDAs) + if(!P.owner || P.toff || P.hidden) + continue + sendPDAs["[P.name]"] = "\ref[P]" + data["possibleRecipients"] = sendPDAs + + data["isMalfAI"] = ((istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) && (user.mind.special_role && user.mind.original == user)) + + return data + /obj/machinery/computer/message_monitor/attack_hand(var/mob/living/user as mob) if(stat & (NOPOWER|BROKEN)) return if(!istype(user)) return - //If the computer is being hacked or is emagged, display the reboot message. - if(hacking || emag) - message = rebootmsg - var/dat = "Message Monitor Console" - dat += "

Message Monitor Console


" - dat += "

" - - if(auth) - dat += "

\[Authenticated\] /" - dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

" - else - dat += "

\[Unauthenticated\] /" - dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

" - - if(hacking || emag) - screen = 2 - else if(!auth || !linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) - if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) message = noserver - screen = 0 - - switch(screen) - //Main menu - if(0) - // = TAB - var/i = 0 - dat += "
[++i]. Link To A Server
" - if(auth) - if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) - dat += "
ERROR: Server not found!
" - else - dat += "
[++i]. View Message Logs
" - dat += "
[++i]. View Request Console Logs
" - dat += "
[++i]. Clear Message Logs
" - dat += "
[++i]. Clear Request Console Logs
" - dat += "
[++i]. Set Custom Key
" - dat += "
[++i]. Send Admin Message
" - dat += "
[++i]. Modify Spam Filter
" - else - for(var/n = ++i; n <= optioncount; n++) - dat += "
[n]. ---------------
" - if((istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) && (user.mind.special_role && user.mind.original == user)) - //Malf/Traitor AIs can bruteforce into the system to gain the Key. - dat += "
*&@#. Bruteforce Key
" - else - dat += "
" - - //Bottom message - if(!auth) - dat += "

Please authenticate with the server in order to show additional options." - else - dat += "

Reg, #514 forbids sending messages to a Head of Staff containing Erotic Rendering Properties." - - //Message Logs - if(1) - var/index = 0 - //var/recipient = "Unspecified" //name of the person - //var/sender = "Unspecified" //name of the sender - //var/message = "Blank" //transferred message - dat += "
Back - Refresh

" - dat += "" - for(var/datum/data_pda_msg/pda in src.linkedServer.pda_msgs) - index++ - if(index > 3000) - break - // Del - Sender - Recepient - Message - // X - Al Green - Your Mom - WHAT UP!? - dat += "" - dat += "
XSenderRecipientMessage
X
[pda.sender][pda.recipient][pda.message]
" - //Hacking screen. - if(2) - if(istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) - dat += "Brute-forcing for server key.
It will take 20 seconds for every character that the password has." - dat += "In the meantime, this console can reveal your true intentions if you let someone access it. Make sure no humans enter the room during that time." - else - //It's the same message as the one above but in binary. Because robots understand binary and humans don't... well I thought it was clever. - dat += {"01000010011100100111010101110100011001010010110
- 10110011001101111011100100110001101101001011011100110011
- 10010000001100110011011110111001000100000011100110110010
- 10111001001110110011001010111001000100000011010110110010
- 10111100100101110001000000100100101110100001000000111011
- 10110100101101100011011000010000001110100011000010110101
- 10110010100100000001100100011000000100000011100110110010
- 10110001101101111011011100110010001110011001000000110011
- 00110111101110010001000000110010101110110011001010111001
- 00111100100100000011000110110100001100001011100100110000
- 10110001101110100011001010111001000100000011101000110100
- 00110000101110100001000000111010001101000011001010010000
- 00111000001100001011100110111001101110111011011110111001
- 00110010000100000011010000110000101110011001011100010000
- 00100100101101110001000000111010001101000011001010010000
- 00110110101100101011000010110111001110100011010010110110
- 10110010100101100001000000111010001101000011010010111001
- 10010000001100011011011110110111001110011011011110110110
- 00110010100100000011000110110000101101110001000000111001
- 00110010101110110011001010110000101101100001000000111100
- 10110111101110101011100100010000001110100011100100111010
- 10110010100100000011010010110111001110100011001010110111
- 00111010001101001011011110110111001110011001000000110100
- 10110011000100000011110010110111101110101001000000110110
- 00110010101110100001000000111001101101111011011010110010
- 10110111101101110011001010010000001100001011000110110001
- 10110010101110011011100110010000001101001011101000010111
- 00010000001001101011000010110101101100101001000000111001
- 10111010101110010011001010010000001101110011011110010000
- 00110100001110101011011010110000101101110011100110010000
- 00110010101101110011101000110010101110010001000000111010
- 00110100001100101001000000111001001101111011011110110110
- 10010000001100100011101010111001001101001011011100110011
- 10010000001110100011010000110000101110100001000000111010
- 001101001011011010110010100101110"} - - //Fake messages - if(3) - dat += "
Back - Reset

" - - dat += {" - - - - "} - //Sender - Sender's Job - Recepient - Message - //Al Green- Your Dad - Your Mom - WHAT UP!? - - dat += {" - - - "} - dat += "
SenderSender's JobRecipientMessage
[customsender][customjob][customrecepient ? customrecepient.owner : "NONE"][custommessage]

Send
" - - //Request Console Logs - if(4) - - var/index = 0 - /* data_rc_msg - X - 5% - var/rec_dpt = "Unspecified" //name of the person - 15% - var/send_dpt = "Unspecified" //name of the sender- 15% - var/message = "Blank" //transferred message - 300px - var/stamp = "Unstamped" - 15% - var/id_auth = "Unauthenticated" - 15% - var/priority = "Normal" - 10% - */ - dat += "
Back - Refresh

" - dat += {" - "} - for(var/datum/data_rc_msg/rc in src.linkedServer.rc_msgs) - index++ - if(index > 3000) - break - // Del - Sender - Recepient - Message - // X - Al Green - Your Mom - WHAT UP!? - dat += {" - "} - dat += "
XSending Dep.Receiving Dep.MessageStampID Auth.Priority.
X
[rc.send_dpt][rc.rec_dpt][rc.message][rc.stamp][rc.id_auth][rc.priority]
" - - //Spam filter modification - if(5) - dat += "
Back - Refresh

" - var/index = 0 - for(var/token in src.linkedServer.spamfilter) - index++ - if(index > 3000) - break - dat += "
[index] \[[token]\]
" - dat += "
" - if (linkedServer.spamfilter.len < linkedServer.spamfilter_limit) - dat += "Add token
" - - - dat += "" - message = defaultmsg - user << browse(dat, "window=message;size=700x700") - onclose(user, "message") - return + tgui_interact(user) /obj/machinery/computer/message_monitor/attack_ai(mob/user as mob) - return src.attack_hand(user) + return attack_hand(user) /obj/machinery/computer/message_monitor/proc/BruteForce(mob/user as mob) if(isnull(linkedServer)) to_chat(user, "Could not complete brute-force: Linked Server Disconnected!") else - var/currentKey = src.linkedServer.decryptkey + var/currentKey = linkedServer.decryptkey to_chat(user, "Brute-force completed! The key is '[currentKey]'.") - src.hacking = 0 + hacking = 0 update_icon() - src.screen = 0 // Return the screen back to normal /obj/machinery/computer/message_monitor/proc/UnmagConsole() - src.emag = 0 + emag = 0 update_icon() /obj/machinery/computer/message_monitor/proc/ResetMessage() @@ -281,227 +169,156 @@ custommessage = "This is a test, please ignore." customjob = "Admin" -/obj/machinery/computer/message_monitor/Topic(href, href_list) +/obj/machinery/computer/message_monitor/tgui_act(action, params) if(..()) - return 1 - if(stat & (NOPOWER|BROKEN)) - return - if(!istype(usr, /mob/living)) - return - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + return TRUE + + switch(action) + if("cleartemp") + temp = null + . = TRUE //Authenticate - if (href_list["auth"]) - if(auth) - auth = 0 - screen = 0 - else - var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null) - if(dkey && dkey != "") - if(src.linkedServer.decryptkey == dkey) - auth = 1 - else - message = incorrectkey - - //Turn the server on/off. - if (href_list["active"]) - if(auth) linkedServer.active = !linkedServer.active + if("auth") + var/dkey = params["key"] + if(dkey && dkey != "") + if(linkedServer.decryptkey == dkey) + auth = TRUE + else + temp = incorrectkey + . = TRUE + if("deauth") + auth = FALSE + . = TRUE //Find a server - if (href_list["find"]) + if("find") if(message_servers && message_servers.len > 1) - src.linkedServer = input(usr,"Please select a server.", "Select a server.", null) as null|anything in message_servers - message = "NOTICE: Server selected." + linkedServer = input(usr,"Please select a server.", "Select a server.", null) as null|anything in message_servers + set_temp("NOTICE: Server selected.", "alert") else if(message_servers && message_servers.len > 0) linkedServer = message_servers[1] - message = "NOTICE: Only Single Server Detected - Server selected." + set_temp("NOTICE: Only Single Server Detected - Server selected.", "average") else - message = noserver - - //View the logs - KEY REQUIRED - if (href_list["view"]) - if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else - if(auth) - src.screen = 1 - - //Clears the logs - KEY REQUIRED - if (href_list["clear"]) - if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else - if(auth) - src.linkedServer.pda_msgs = list() - message = "NOTICE: Logs cleared." - //Clears the request console logs - KEY REQUIRED - if (href_list["clearr"]) - if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else - if(auth) - src.linkedServer.rc_msgs = list() - message = "NOTICE: Logs cleared." - //Change the password - KEY REQUIRED - if (href_list["pass"]) - if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else - if(auth) - var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null) - if(dkey && dkey != "") - if(src.linkedServer.decryptkey == dkey) - var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):")) - if(length(newkey) <= 3) - message = "NOTICE: Decryption key too short!" - else if(length(newkey) > 16) - message = "NOTICE: Decryption key too long!" - else if(newkey && newkey != "") - src.linkedServer.decryptkey = newkey - message = "NOTICE: Decryption key set." - else - message = incorrectkey - + temp = noserver //Hack the Console to get the password - if (href_list["hack"]) + if("hack") if((istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)) && (usr.mind.special_role && usr.mind.original == usr)) - src.hacking = 1 - src.screen = 2 + hacking = 1 update_icon() //Time it takes to bruteforce is dependant on the password length. - spawn(100*length(src.linkedServer.decryptkey)) - if(src && src.linkedServer && usr) + spawn(100*length(linkedServer.decryptkey)) + if(src && linkedServer && usr) BruteForce(usr) + + if(!auth) + return + + if(!linkedServer || linkedServer.stat & (NOPOWER|BROKEN)) + temp = noserver + return TRUE + + switch(action) + //Turn the server on/off. + if("active") + linkedServer.active = !linkedServer.active + . = TRUE + //Clears the logs - KEY REQUIRED + if("del_pda") + linkedServer.pda_msgs = list() + set_temp("NOTICE: Logs cleared.", "average") + . = TRUE + //Clears the request console logs - KEY REQUIRED + if("del_rc") + linkedServer.rc_msgs = list() + set_temp("NOTICE: Logs cleared.", "average") + . = TRUE + //Change the password - KEY REQUIRED + if("pass") + var/dkey = trim(input(usr, "Please enter the current decryption key.") as text|null) + if(dkey && dkey != "") + if(linkedServer.decryptkey == dkey) + var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):")) + if(length(newkey) <= 3) + set_temp("NOTICE: Decryption key too short!", "average") + else if(length(newkey) > 16) + set_temp("NOTICE: Decryption key too long!", "average") + else if(newkey && newkey != "") + linkedServer.decryptkey = newkey + set_temp("NOTICE: Decryption key set.", "average") + else + temp = incorrectkey + . = TRUE //Delete the log. - if (href_list["delete"]) - //Are they on the view logs screen? - if(screen == 1) - if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else //if(istype(href_list["delete"], /datum/data_pda_msg)) - src.linkedServer.pda_msgs -= locate(href_list["delete"]) - message = "NOTICE: Log Deleted!" - //Delete the request console log. - if (href_list["deleter"]) - //Are they on the view logs screen? - if(screen == 4) - if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else //if(istype(href_list["delete"], /datum/data_pda_msg)) - src.linkedServer.rc_msgs -= locate(href_list["deleter"]) - message = "NOTICE: Log Deleted!" - //Create a custom message - if (href_list["msg"]) - if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver + if("delete") + if(params["type"] == "pda") + linkedServer.pda_msgs -= locate(params["id"]) else - if(auth) - src.screen = 3 + linkedServer.rc_msgs -= locate(params["id"]) + set_temp("NOTICE: Log Deleted!", "average") + . = TRUE //Fake messaging selection - KEY REQUIRED - if (href_list["select"]) - if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - screen = 0 + if("set_sender") + customsender = sanitize(params["val"]) + . = TRUE + if("set_sender_job") + customjob = sanitize(params["val"]) + . = TRUE + if("set_recipient") + var/ref = params["val"] + var/obj/item/device/pda/P = locate(ref) + if(!istype(P) || !P.owner || P.toff || P.hidden) + return FALSE + customrecepient = P + . = TRUE + if("set_message") + custommessage = sanitize(params["val"]) + . = TRUE + if("send_message") + if(isnull(customsender) || customsender == "") + customsender = "UNKNOWN" + + if(isnull(customrecepient)) + set_temp("NOTICE: No recepient selected!", "average") + return TRUE + + if(isnull(custommessage) || custommessage == "") + set_temp("NOTICE: No message entered!", "average") + return TRUE + + var/obj/item/device/pda/PDARec = null + for(var/obj/item/device/pda/P in PDAs) + if(!P.owner || P.toff || P.hidden) continue + if(P.owner == customsender) + PDARec = P + //Sender isn't faking as someone who exists + if(isnull(PDARec)) + linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]") + customrecepient.new_message(customsender, customsender, customjob, custommessage) + //Sender is faking as someone who exists else - switch(href_list["select"]) + linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]") + customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]"))) - //Reset - if("Reset") - ResetMessage() + if(!customrecepient.conversations.Find("\ref[PDARec]")) + customrecepient.conversations.Add("\ref[PDARec]") - //Select Your Name - if("Sender") - customsender = sanitize(input(usr, "Please enter the sender's name.") as text|null) + customrecepient.new_message(PDARec, custommessage) + //Finally.. + ResetMessage() + . = TRUE - //Select Receiver - if("Recepient") - //Get out list of viable PDAs - var/list/obj/item/device/pda/sendPDAs = list() - for(var/obj/item/device/pda/P in PDAs) - if(!P.owner || P.toff || P.hidden) continue - sendPDAs += P - if(PDAs && PDAs.len > 0) - customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortAtom(sendPDAs) - else - customrecepient = null + if("addtoken") + linkedServer.spamfilter += input(usr,"Enter text you want to be filtered out","Token creation") as text|null + . = TRUE - //Enter custom job - if("RecJob") - customjob = sanitize(input(usr, "Please enter the sender's job.") as text|null) + if("deltoken") + var/tokennum = text2num(params["deltoken"]) + linkedServer.spamfilter.Cut(tokennum, tokennum + 1) + . = TRUE - //Enter message - if("Message") - custommessage = input(usr, "Please enter your message.") as text|null - custommessage = sanitize(custommessage) - - //Send message - if("Send") - - if(isnull(customsender) || customsender == "") - customsender = "UNKNOWN" - - if(isnull(customrecepient)) - message = "NOTICE: No recepient selected!" - return src.attack_hand(usr) - - if(isnull(custommessage) || custommessage == "") - message = "NOTICE: No message entered!" - return src.attack_hand(usr) - - var/obj/item/device/pda/PDARec = null - for (var/obj/item/device/pda/P in PDAs) - if (!P.owner || P.toff || P.hidden) continue - if(P.owner == customsender) - PDARec = P - //Sender isn't faking as someone who exists - if(isnull(PDARec)) - src.linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]") - customrecepient.new_message(customsender, customsender, customjob, custommessage) - //Sender is faking as someone who exists - else - - src.linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]") - customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]"))) - - if(!customrecepient.conversations.Find("\ref[PDARec]")) - customrecepient.conversations.Add("\ref[PDARec]") - - customrecepient.new_message(PDARec, custommessage) - //Finally.. - ResetMessage() - - //Request Console Logs - KEY REQUIRED - if(href_list["viewr"]) - if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else - if(auth) - src.screen = 4 - - //to_chat(usr,href_list["select"]) - - if(href_list["spam"]) - if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else - if(auth) - src.screen = 5 - - if(href_list["addtoken"]) - if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else - src.linkedServer.spamfilter += input(usr,"Enter text you want to be filtered out","Token creation") as text|null - - if(href_list["deltoken"]) - if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) - message = noserver - else - var/tokennum = text2num(href_list["deltoken"]) - src.linkedServer.spamfilter.Cut(tokennum,tokennum+1) - - if (href_list["back"]) - src.screen = 0 - - return src.attack_hand(usr) +/obj/machinery/computer/message_monitor/proc/set_temp(text = "", style = "info", update_now = FALSE) + temp = list(text = text, style = style) + if(update_now) + SStgui.update_uis(src) /obj/item/weapon/paper/monitorkey name = "Monitor Decryption Key" diff --git a/code/game/machinery/computer/shutoff_monitor.dm b/code/game/machinery/computer/shutoff_monitor.dm index 89cd4127db..8cc101d804 100644 --- a/code/game/machinery/computer/shutoff_monitor.dm +++ b/code/game/machinery/computer/shutoff_monitor.dm @@ -5,23 +5,19 @@ icon_screen = "power_monitor" light_color = "#a97faa" circuit = /obj/item/weapon/circuitboard/shutoff_monitor - var/datum/nano_module/shutoff_monitor/monitor + var/datum/tgui_module/shutoff_monitor/monitor /obj/machinery/computer/shutoff_monitor/New() ..() monitor = new(src) /obj/machinery/computer/shutoff_monitor/Destroy() - qdel(monitor) - monitor = null + QDEL_NULL(monitor) ..() /obj/machinery/computer/shutoff_monitor/attack_hand(var/mob/user as mob) ..() - ui_interact(user) - -/obj/machinery/computer/shutoff_monitor/ui_interact(mob/user, ui_key = "shutoff_monitor", var/datum/nanoui/ui = null, var/force_open = 1) - monitor.ui_interact(user, ui_key, ui, force_open) + monitor.tgui_interact(user) /obj/machinery/computer/shutoff_monitor/update_icon() ..() diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm index 1a64db7389..bde923a217 100644 --- a/code/game/machinery/computer/skills.dm +++ b/code/game/machinery/computer/skills.dm @@ -1,5 +1,11 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +#define GENERAL_RECORD_LIST 2 +#define GENERAL_RECORD_MAINT 3 +#define GENERAL_RECORD_DATA 4 + +#define FIELD(N, V, E) list(field = N, value = V, edit = E) + /obj/machinery/computer/skills//TODO:SANITY name = "employment records console" desc = "Used to view, edit and maintain employment records." @@ -16,20 +22,40 @@ var/screen = null var/datum/data/record/active1 = null var/a_id = null - var/temp = null + var/list/temp = null var/printing = null var/can_change_id = 0 - var/list/Perp - var/tempname = null - //Sorting Variables - var/sortBy = "name" - var/order = 1 // -1 = Descending - 1 = Ascending + // The below are used to make modal generation more convenient + var/static/list/field_edit_questions + var/static/list/field_edit_choices + +/obj/machinery/computer/skills/Initialize() + ..() + field_edit_questions = list( + // General + "name" = "Please input new name:", + "id" = "Please input new ID:", + "sex" = "Please select new sex:", + "age" = "Please input new age:", + "fingerprint" = "Please input new fingerprint hash:", + ) + field_edit_choices = list( + // General + "sex" = all_genders_text_list, + "p_stat" = list("*Deceased*", "*SSD*", "Active", "Physically Unfit", "Disabled"), + "m_stat" = list("*Insane*", "*Unstable*", "*Watch*", "Stable"), + ) + +/obj/machinery/computer/skills/Destroy() + active1 = null + return ..() /obj/machinery/computer/skills/attackby(obj/item/O as obj, var/mob/user) if(istype(O, /obj/item/weapon/card/id) && !scan && user.unEquip(O)) O.loc = src scan = O to_chat(user, "You insert [O].") + tgui_interact(user) else ..() @@ -43,380 +69,271 @@ if (using_map && !(src.z in using_map.contact_levels)) to_chat(user, "Unable to establish a connection: You're too far away from the station!") return - var/dat + tgui_interact(user) - if (temp) - dat = text("[]

Clear Screen", temp, src) - else - dat = text("Confirm Identity: []
", src, (scan ? text("[]", scan.name) : "----------")) - if (authenticated) - switch(screen) - if(1.0) - dat += {" -

"} - dat += text("Search Records
", src) - dat += text("New Record
", src) - dat += {" -

- - - - -
Records:
- - - - - - -"} - if(!isnull(data_core.general)) - for(var/datum/data/record/R in sortRecord(data_core.general, sortBy, order)) - for(var/datum/data/record/E in data_core.security) - var/background - dat += text("", background, src, R, R.fields["name"]) - dat += text("", R.fields["id"]) - dat += text("", R.fields["rank"]) - dat += text("", R.fields["fingerprint"]) - dat += "
NameIDRankFingerprints
[][][][]

" - dat += text("Record Maintenance

", src) - dat += text("{Log Out}",src) - if(2.0) - dat += "Records Maintenance
" - dat += "
Delete All Records

Back" - if(3.0) - dat += "
Employment Record

" - if ((istype(active1, /datum/data/record) && data_core.general.Find(active1))) - var/icon/front = active1.fields["photo_front"] - var/icon/side = active1.fields["photo_side"] - user << browse_rsc(front, "front.png") - user << browse_rsc(side, "side.png") - dat += "" - - dat += "
" - dat += "Name: [active1.fields["name"]]
" - dat += "ID: [active1.fields["id"]]
\n" - dat += "Entity Classification: [active1.fields["brain_type"]]
\n" - dat += "Sex: [active1.fields["sex"]]
\n" - dat += "Age: [active1.fields["age"]]
\n" - dat += "Rank: [active1.fields["rank"]]
\n" - dat += "Fingerprint: [active1.fields["fingerprint"]]
\n" - dat += "Physical Status: [active1.fields["p_stat"]]
\n" - dat += "Mental Status: [active1.fields["m_stat"]]

\n" +/obj/machinery/computer/skills/tgui_interact(mob/user, datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GeneralRecords", "Employee Records") // 800, 380 + ui.open() + ui.set_autoupdate(FALSE) - dat += "Employment/skills summary:
" - dat += decode(active1.fields["notes"]) - dat += "


" - var/counter = 1 - while(src.active1.fields[text("com_[]", counter)]) - dat += text("[]
Delete Entry

", src.active1.fields[text("com_[]", counter)], src, counter) - counter++ - dat += "Add Entry

Photo:
" - dat += "
" - else - dat += "General Record Lost!
" - dat += text("\nDelete Record (ALL)

\nPrint Record
\nBack
", src, src, src) - if(4.0) - if(!Perp.len) - dat += text("ERROR. String could not be located.

Back", src) - else - dat += {" - - "} - dat += text("", tempname) - dat += {" - -
Search Results for '[]':
- - - - - - - "} - for(var/i=1, i<=Perp.len, i += 2) - var/crimstat = "" - var/datum/data/record/R = Perp[i] - if(istype(Perp[i+1],/datum/data/record/)) - var/datum/data/record/E = Perp[i+1] - crimstat = E.fields["criminal"] - var/background - background = "'background-color:#00FF7F;'" - dat += text("", background, src, R, R.fields["name"]) - dat += text("", R.fields["id"]) - dat += text("", R.fields["rank"]) - dat += text("", R.fields["fingerprint"]) - dat += text("", crimstat) - dat += "
NameIDRankFingerprints
[][][][][]

" - dat += text("
Return to index.", src) +/obj/machinery/computer/skills/tgui_data(mob/user) + var/data[0] + data["temp"] = temp + data["scan"] = scan ? scan.name : null + data["authenticated"] = authenticated + data["rank"] = rank + data["screen"] = screen + data["printing"] = printing + data["isAI"] = isAI(user) + data["isRobot"] = isrobot(user) + if(authenticated) + switch(screen) + if(GENERAL_RECORD_LIST) + if(!isnull(data_core.general)) + var/list/records = list() + data["records"] = records + for(var/datum/data/record/R in sortRecord(data_core.general)) + records[++records.len] = list( + "ref" = "\ref[R]", + "id" = R.fields["id"], + "name" = R.fields["name"], + "b_dna" = R.fields["b_dna"]) + if(GENERAL_RECORD_DATA) + var/list/general = list() + data["general"] = general + if(istype(active1, /datum/data/record) && data_core.general.Find(active1)) + var/list/fields = list() + general["fields"] = fields + fields[++fields.len] = FIELD("Name", active1.fields["name"], "name") + fields[++fields.len] = FIELD("ID", active1.fields["id"], "id") + fields[++fields.len] = FIELD("Sex", active1.fields["sex"], "sex") + fields[++fields.len] = FIELD("Age", active1.fields["age"], "age") + fields[++fields.len] = FIELD("Fingerprint", active1.fields["fingerprint"], "fingerprint") + fields[++fields.len] = FIELD("Physical Status", active1.fields["p_stat"], null) + fields[++fields.len] = FIELD("Mental Status", active1.fields["m_stat"], null) + var/list/photos = list() + general["photos"] = photos + photos[++photos.len] = active1.fields["photo-south"] + photos[++photos.len] = active1.fields["photo-west"] + general["has_photos"] = (active1.fields["photo-south"] || active1.fields["photo-west"] ? 1 : 0) + if(!active1.fields["comments"] || !islist(active1.fields["comments"])) + active1.fields["comments"] = list() + general["skills"] = active1.fields["notes"] + general["comments"] = active1.fields["comments"] + general["empty"] = 0 else - else - dat += text("{Log In}", src) - user << browse(text("Employment Records[]", dat), "window=secure_rec;size=600x400") - onclose(user, "secure_rec") - return + general["empty"] = 1 -/*Revised /N -I can't be bothered to look more of the actual code outside of switch but that probably needs revising too. -What a mess.*/ -/obj/machinery/computer/skills/Topic(href, href_list) + data["modal"] = tgui_modal_data(src) + return data + +/obj/machinery/computer/skills/tgui_act(action, params) if(..()) - return 1 - if (!( data_core.general.Find(active1) )) + return TRUE + + add_fingerprint(usr) + + if(!data_core.general.Find(active1)) active1 = null - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - switch(href_list["choice"]) -// SORTING! - if("Sorting") - // Reverse the order if clicked twice - if(sortBy == href_list["sort"]) - if(order == 1) - order = -1 - else - order = 1 - else - // New sorting order! - sortBy = href_list["sort"] - order = initial(order) -//BASIC FUNCTIONS - if("Clear Screen") - temp = null - if ("Return") - screen = 1 + . = TRUE + if(tgui_act_modal(action, params)) + return + + switch(action) + if("scan") + if(scan) + scan.forceMove(loc) + if(ishuman(usr) && !usr.get_active_hand()) + usr.put_in_hands(scan) + scan = null + else + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.forceMove(src) + scan = I + if("cleartemp") + temp = null + if("login") + var/login_type = text2num(params["login_type"]) + if(login_type == LOGIN_TYPE_NORMAL && istype(scan)) + if(check_access(scan)) + authenticated = scan.registered_name + rank = scan.assignment + else if(login_type == LOGIN_TYPE_AI && isAI(usr)) + authenticated = usr.name + rank = "AI" + else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr)) + authenticated = usr.name + var/mob/living/silicon/robot/R = usr + rank = "[R.modtype] [R.braintype]" + if(authenticated) active1 = null + screen = GENERAL_RECORD_LIST + else + . = FALSE + + if(.) + return - if("Confirm Identity") - if (scan) - if(istype(usr,/mob/living/carbon/human) && !usr.get_active_hand()) + if(authenticated) + . = TRUE + switch(action) + if("logout") + if(scan) + scan.forceMove(loc) + if(ishuman(usr) && !usr.get_active_hand()) usr.put_in_hands(scan) - else - scan.loc = get_turf(src) scan = null - else - var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) - I.loc = src - scan = I - - if("Log Out") authenticated = null screen = null active1 = null - - if("Log In") - if (istype(usr, /mob/living/silicon/ai)) - src.active1 = null - src.authenticated = usr.name - src.rank = "AI" - src.screen = 1 - else if (istype(usr, /mob/living/silicon/robot)) - src.active1 = null - src.authenticated = usr.name - var/mob/living/silicon/robot/R = usr - src.rank = R.braintype - src.screen = 1 - else if (istype(scan, /obj/item/weapon/card/id)) - active1 = null - if(check_access(scan)) - authenticated = scan.registered_name - rank = scan.assignment - screen = 1 -//RECORD FUNCTIONS - if("Search Records") - var/t1 = input("Search String: (Partial Name or ID or Fingerprints or Rank)", "Secure. records", null, null) as text - if ((!( t1 ) || usr.stat || !( authenticated ) || usr.restrained() || !in_range(src, usr))) - return - Perp = new/list() - t1 = lowertext(t1) - var/list/components = splittext(t1, " ") - if(components.len > 5) - return //Lets not let them search too greedily. - for(var/datum/data/record/R in data_core.general) - var/temptext = R.fields["name"] + " " + R.fields["id"] + " " + R.fields["fingerprint"] + " " + R.fields["rank"] - for(var/i = 1, i<=components.len, i++) - if(findtext(temptext,components[i])) - var/prelist = new/list(2) - prelist[1] = R - Perp += prelist - for(var/i = 1, i<=Perp.len, i+=2) - for(var/datum/data/record/E in data_core.security) - var/datum/data/record/R = Perp[i] - if ((E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])) - Perp[i+1] = E - tempname = t1 - screen = 4 - - if("Record Maintenance") - screen = 2 + if("screen") + screen = clamp(text2num(params["screen"]) || 0, GENERAL_RECORD_LIST, GENERAL_RECORD_MAINT) active1 = null - - if ("Browse Record") - var/datum/data/record/R = locate(href_list["d_rec"]) - if (!( data_core.general.Find(R) )) - temp = "Record Not Found!" - else - for(var/datum/data/record/E in data_core.security) - active1 = R - screen = 3 - -/* if ("Search Fingerprints") - var/t1 = input("Search String: (Fingerprint)", "Secure. records", null, null) as text - if ((!( t1 ) || usr.stat || !( authenticated ) || usr.restrained() || (!in_range(src, usr)) && (!istype(usr, /mob/living/silicon)))) - return - active1 = null - t1 = lowertext(t1) - for(var/datum/data/record/R in data_core.general) - if (lowertext(R.fields["fingerprint"]) == t1) - active1 = R - if (!( active1 )) - temp = text("Could not locate record [].", t1) - else - for(var/datum/data/record/E in data_core.security) - if ((E.fields["name"] == active1.fields["name"] || E.fields["id"] == active1.fields["id"])) - screen = 3 */ - - if ("Print Record") - if (!( printing )) - printing = 1 - sleep(50) - var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( loc ) - P.info = "
Employment Record

" - if ((istype(active1, /datum/data/record) && data_core.general.Find(active1))) - P.info += text("Name: [] ID: []
\nSex: []
\nAge: []
\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
\nEmployment/Skills Summary:
\n[]
", active1.fields["name"], active1.fields["id"], active1.fields["sex"], active1.fields["age"], active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"], decode(active1.fields["notes"])) - else - P.info += "General Record Lost!
" - P.info += "" - if(active1) - P.name = "Employment Record ([active1.fields["name"]])" - else - P.name = "Employment Record (Unknown/Invald Entry)" - log_debug("[usr] ([usr.ckey]) attempted to print a null employee record, this should be investigated.") - printing = null -// Add comment - if ("add_c") - if (!( istype(src.active1, /datum/data/record) )) - return - var/a1 = src.active1 - var/t1 = sanitize(input("Add Comment:", "Emp. records", null, null) as message) - if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) - return - var/counter = 1 - while(src.active1.fields[text("com_[]", counter)]) - counter++ - src.active1.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD")] [stationtime2text()], [game_year]
[t1]") -// Delete comment - if ("del_c") - var/target = href_list["del_c"] - if (istype(src.active1, /datum/data/record) && src.active1.fields["com_[target]"]) - src.active1.fields["com_[target]"] = "Deleted" - - -//RECORD DELETE - if ("Delete All Records") - temp = "" - temp += "Are you sure you wish to delete all Employment records?
" - temp += "Yes
" - temp += "No" - - if ("Purge All Records") - if(PDA_Manifest.len) + if("del_all") + if(PDA_Manifest) PDA_Manifest.Cut() - for(var/datum/data/record/R in data_core.security) + for(var/datum/data/record/R in data_core.general) qdel(R) - temp = "All Employment records deleted." + set_temp("All employment records deleted.") + if("del_r") + if(PDA_Manifest) + PDA_Manifest.Cut() + if(active1) + for(var/datum/data/record/R in data_core.medical) + if ((R.fields["name"] == active1.fields["name"] || R.fields["id"] == active1.fields["id"])) + qdel(R) + set_temp("Employment record deleted.") + QDEL_NULL(active1) + if("d_rec") + var/datum/data/record/general_record = locate(params["d_rec"] || "") + if(!data_core.general.Find(general_record)) + set_temp("Record not found.", "danger") + return - if ("Delete Record (ALL)") - if (active1) - temp = "
Are you sure you wish to delete the record (ALL)?
" - temp += "Yes
" - temp += "No" -//RECORD CREATE - if ("New Record (General)") - if(PDA_Manifest.len) + active1 = general_record + screen = GENERAL_RECORD_DATA + if("new") + if(PDA_Manifest) PDA_Manifest.Cut() active1 = data_core.CreateGeneralRecord() + screen = GENERAL_RECORD_DATA + set_temp("Employment record created.", "success") + if("del_c") + var/index = text2num(params["del_c"] || "") + if(!index || !istype(active1, /datum/data/record)) + return -//FIELD FUNCTIONS - if ("Edit Field") - var/a1 = active1 - switch(href_list["field"]) - if("name") - if (istype(active1, /datum/data/record)) - var/t1 = sanitizeName(input("Please input name:", "Secure. records", active1.fields["name"], null) as text) - if ((!( t1 ) || !length(trim(t1)) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon)))) || active1 != a1) - return - active1.fields["name"] = t1 - if("id") - if (istype(active1, /datum/data/record)) - var/t1 = sanitize(input("Please input id:", "Secure. records", active1.fields["id"], null) as text) - if ((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) - return - active1.fields["id"] = t1 - if("fingerprint") - if (istype(active1, /datum/data/record)) - var/t1 = sanitize(input("Please input fingerprint hash:", "Secure. records", active1.fields["fingerprint"], null) as text) - if ((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) - return - active1.fields["fingerprint"] = t1 - if("sex") - if (istype(active1, /datum/data/record)) - if (active1.fields["sex"] == "Male") - active1.fields["sex"] = "Female" - else - active1.fields["sex"] = "Male" - if("age") - if (istype(active1, /datum/data/record)) - var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num - if ((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) - return - active1.fields["age"] = t1 - if("rank") - var/list/L = list( "Head of Personnel", "Colony Director", "AI" ) - //This was so silly before the change. Now it actually works without beating your head against the keyboard. /N - if ((istype(active1, /datum/data/record) && L.Find(rank))) - temp = "
Rank:
" - temp += "" - else - alert(usr, "You do not have the required rank to do this!") - if("species") - if (istype(active1, /datum/data/record)) - var/t1 = sanitize(input("Please enter race:", "General records", active1.fields["species"], null) as message) - if ((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) - return - active1.fields["species"] = t1 + var/list/comments = active1.fields["comments"] + index = clamp(index, 1, length(comments)) + if(comments[index]) + comments.Cut(index, index + 1) + if("print_p") + if(!printing) + printing = TRUE + // playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE) + SStgui.update_uis(src) + addtimer(CALLBACK(src, .proc/print_finish), 5 SECONDS) + else + return FALSE -//TEMPORARY MENU FUNCTIONS - else//To properly clear as per clear screen. - temp=null - switch(href_list["choice"]) - if ("Change Rank") - if (active1) - if(PDA_Manifest.len) - PDA_Manifest.Cut() - active1.fields["rank"] = href_list["rank"] - if(href_list["rank"] in joblist) - active1.fields["real_rank"] = href_list["real_rank"] - - if ("Delete Record (ALL) Execute") - if (active1) - if(PDA_Manifest.len) - PDA_Manifest.Cut() - for(var/datum/data/record/R in data_core.medical) - if ((R.fields["name"] == active1.fields["name"] || R.fields["id"] == active1.fields["id"])) - qdel(R) - else - qdel(active1) +/** + * Called in tgui_act() to process modal actions + * + * Arguments: + * * action - The action passed by tgui + * * params - The params passed by tgui + */ +/obj/machinery/computer/skills/proc/tgui_act_modal(action, params) + . = TRUE + var/id = params["id"] // The modal's ID + var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"] + switch(tgui_modal_act(src, action, params)) + if(TGUI_MODAL_OPEN) + switch(id) + if("edit") + var/field = arguments["field"] + if(!length(field) || !field_edit_questions[field]) + return + var/question = field_edit_questions[field] + var/choices = field_edit_choices[field] + if(length(choices)) + tgui_modal_choice(src, id, question, arguments = arguments, value = arguments["value"], choices = choices) else - temp = "This function does not appear to be working at the moment. Our apologies." + tgui_modal_input(src, id, question, arguments = arguments, value = arguments["value"]) + if("add_c") + tgui_modal_input(src, id, "Please enter your message:") + else + return FALSE + if(TGUI_MODAL_ANSWER) + var/answer = params["answer"] + switch(id) + if("edit") + var/field = arguments["field"] + if(!length(field) || !field_edit_questions[field]) + return + var/list/choices = field_edit_choices[field] + if(length(choices) && !(answer in choices)) + return - add_fingerprint(usr) - updateUsrDialog() - return + if(field == "age") + answer = text2num(answer) + + if(istype(active1) && (field in active1.fields)) + active1.fields[field] = answer + . = TRUE + if("add_c") + if(!length(answer) || !istype(active1) || !length(authenticated)) + return + active1.fields["comments"] += list(list( + header = "Made by [authenticated] ([rank]) at [worldtime2stationtime(world.time)]", + text = answer + )) + else + return FALSE + else + return FALSE + +/** + * Called when the print timer finishes + */ +/obj/machinery/computer/skills/proc/print_finish() + var/obj/item/weapon/paper/P = new(loc) + P.info = "
Medical Record

" + if(istype(active1, /datum/data/record) && data_core.general.Find(active1)) + P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]] +
\nSex: [active1.fields["sex"]] +
\nAge: [active1.fields["age"]] +
\nFingerprint: [active1.fields["fingerprint"]] +
\nPhysical Status: [active1.fields["p_stat"]] +
\nMental Status: [active1.fields["m_stat"]]
+
\nEmployment/Skills Summary: [active1.fields["notes"]] +
\n +
Comments/Log

"} + for(var/c in active1.fields["comments"]) + P.info += "[c]
" + else + P.info += "General Record Lost!
" + P.info += "" + P.name = "paper - 'Employment Record: [active1.fields["name"]]'" + printing = FALSE + SStgui.update_uis(src) + +/** + * Sets a temporary message to display to the user + * + * Arguments: + * * text - Text to display, null/empty to clear the message from the UI + * * style - The style of the message: (color name), info, success, warning, danger, virus + */ +/obj/machinery/computer/skills/proc/set_temp(text = "", style = "info", update_now = FALSE) + temp = list(text = text, style = style) + if(update_now) + SStgui.update_uis(src) /obj/machinery/computer/skills/emp_act(severity) if(stat & (BROKEN|NOPOWER)) diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index 8bd2f91f89..5cb000484d 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -6,15 +6,15 @@ icon_screen = "alert:0" light_color = "#e6ffff" circuit = /obj/item/weapon/circuitboard/stationalert_engineering - var/datum/nano_module/alarm_monitor/alarm_monitor - var/monitor_type = /datum/nano_module/alarm_monitor/engineering + var/datum/tgui_module/alarm_monitor/alarm_monitor + var/monitor_type = /datum/tgui_module/alarm_monitor/engineering /obj/machinery/computer/station_alert/security - monitor_type = /datum/nano_module/alarm_monitor/security + monitor_type = /datum/tgui_module/alarm_monitor/security circuit = /obj/item/weapon/circuitboard/stationalert_security /obj/machinery/computer/station_alert/all - monitor_type = /datum/nano_module/alarm_monitor/all + monitor_type = /datum/tgui_module/alarm_monitor/all circuit = /obj/item/weapon/circuitboard/stationalert_all /obj/machinery/computer/station_alert/Initialize() @@ -31,18 +31,18 @@ add_fingerprint(user) if(stat & (BROKEN|NOPOWER)) return - interact(user) + tgui_interact(user) return /obj/machinery/computer/station_alert/attack_hand(mob/user) add_fingerprint(user) if(stat & (BROKEN|NOPOWER)) return - interact(user) + tgui_interact(user) return -/obj/machinery/computer/station_alert/interact(mob/user) - alarm_monitor.ui_interact(user) +/obj/machinery/computer/station_alert/tgui_interact(mob/user) + alarm_monitor.tgui_interact(user) /obj/machinery/computer/station_alert/update_icon() if(!(stat & (BROKEN|NOPOWER))) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 2ec9c0043b..73ed4dc72e 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -740,32 +740,52 @@ About the new airlock wires panel: return /obj/machinery/door/airlock/attack_ai(mob/user as mob) - ui_interact(user) + tgui_interact(user) -/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/data[0] +/obj/machinery/door/airlock/attack_ghost(mob/user) + tgui_interact(user) - data["main_power_loss"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) - data["backup_power_loss"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) - data["electrified"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) - data["open"] = !density - - var/commands[0] - commands[++commands.len] = list("name" = "IdScan", "command"= "idscan", "active" = !aiDisabledIdScanner, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) - commands[++commands.len] = list("name" = "Bolts", "command"= "bolts", "active" = !locked, "enabled" = "Raised ", "disabled" = "Dropped", "danger" = 0, "act" = 0) - commands[++commands.len] = list("name" = "Bolt Lights", "command"= "lights", "active" = lights, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) - commands[++commands.len] = list("name" = "Safeties", "command"= "safeties", "active" = safe, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) - commands[++commands.len] = list("name" = "Timing", "command"= "timing", "active" = normalspeed, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) - commands[++commands.len] = list("name" = "Door State", "command"= "open", "active" = density, "enabled" = "Closed", "disabled" = "Opened", "danger" = 0, "act" = 0) - - data["commands"] = commands - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls", 450, 350, state = state) - ui.set_initial_data(data) +/obj/machinery/door/airlock/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AiAirlock", name) ui.open() - ui.set_auto_update(1) + return TRUE + +/obj/machinery/door/airlock/tgui_data(mob/user) + var/list/data = list() + + var/list/power = list() + power["main"] = main_power_lost_until > 0 ? 0 : 2 + power["main_timeleft"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) + power["backup"] = backup_power_lost_until > 0 ? 0 : 2 + power["backup_timeleft"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) + data["power"] = power + + data["shock"] = (electrified_until == 0) ? 2 : 0 + data["shock_timeleft"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) + data["id_scanner"] = !aiDisabledIdScanner + data["locked"] = locked // bolted + data["lights"] = lights // bolt lights + data["safe"] = safe // safeties + data["speed"] = normalspeed // safe speed + data["welded"] = welded // welded + data["opened"] = !density // opened + + var/list/wire = list() + wire["main_1"] = !wires.is_cut(WIRE_MAIN_POWER1) + wire["main_2"] = !wires.is_cut(WIRE_MAIN_POWER2) + wire["backup_1"] = !wires.is_cut(WIRE_BACKUP_POWER1) + wire["backup_2"] = !wires.is_cut(WIRE_BACKUP_POWER2) + wire["shock"] = !wires.is_cut(WIRE_ELECTRIFY) + wire["id_scanner"] = !wires.is_cut(WIRE_IDSCAN) + wire["bolts"] = !wires.is_cut(WIRE_DOOR_BOLTS) + wire["lights"] = !wires.is_cut(WIRE_BOLT_LIGHT) + wire["safe"] = !wires.is_cut(WIRE_SAFETY) + wire["timing"] = !wires.is_cut(WIRE_SPEED) + + data["wires"] = wire + return data /obj/machinery/door/airlock/proc/hack(mob/user as mob) if(src.aiHacking==0) @@ -844,80 +864,106 @@ About the new airlock wires panel: ..(user) return -/obj/machinery/door/airlock/CanUseTopic(var/mob/user) - if(operating < 0) //emagged - to_chat(user, "Unable to interface: Internal error.") - return STATUS_CLOSE - if(issilicon(user) && !src.canAIControl()) - if(src.canAIHack(user)) - src.hack(user) - else - if (src.isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it. - to_chat(user, "Unable to interface: Connection timed out.") - else - to_chat(user, "Unable to interface: Connection refused.") - return STATUS_CLOSE - - return ..() - -/obj/machinery/door/airlock/Topic(href, href_list) +/obj/machinery/door/airlock/tgui_act(action, params) if(..()) - return 1 + return TRUE + if(!user_allowed(usr)) + return TRUE - var/activate = text2num(href_list["activate"]) - switch (href_list["command"]) - if("idscan") - set_idscan(activate, 1) - if("main_power") + switch(action) + if("disrupt-main") if(!main_power_lost_until) - src.loseMainPower() - if("backup_power") + loseMainPower() + update_icon() + else + to_chat(usr, "Main power is already offline.") + . = TRUE + if("disrupt-backup") if(!backup_power_lost_until) - src.loseBackupPower() - if("bolts") - if(wires.is_cut(WIRE_DOOR_BOLTS)) - to_chat(usr, "The door bolt control wire is cut - Door bolts permanently dropped.") - else if(activate && src.lock()) - to_chat(usr, "The door bolts have been dropped.") - else if(!activate && src.unlock()) - to_chat(usr, "The door bolts have been raised.") - if("electrify_temporary") - electrify(30 * activate, 1) - if("electrify_permanently") - electrify(-1 * activate, 1) - if("open") - if(src.welded) - to_chat(usr, "The airlock has been welded shut!") - else if(src.locked) - to_chat(usr, "The door bolts are down!") - else if(activate && density) - open() - else if(!activate && !density) - close() - if("safeties") - set_safeties(!activate, 1) - if("timing") - // Door speed control - if(wires.is_cut(WIRE_SPEED)) - to_chat(usr, "The timing wire is cut - Cannot alter timing.") - else if (activate && src.normalspeed) - normalspeed = 0 - else if (!activate && !src.normalspeed) - normalspeed = 1 - if("lights") - // Bolt lights + loseBackupPower() + update_icon() + else + to_chat(usr, "Backup power is already offline.") + . = TRUE + if("shock-restore") + electrify(0, 1) + . = TRUE + if("shock-temp") + electrify(30, 1) + . = TRUE + if("shock-perm") + electrify(-1, 1) + . = TRUE + if("idscan-toggle") + set_idscan(aiDisabledIdScanner, 1) + . = TRUE + // if("emergency-toggle") + // toggle_emergency(usr) + // . = TRUE + if("bolt-toggle") + toggle_bolt(usr) + . = TRUE + if("light-toggle") if(wires.is_cut(WIRE_BOLT_LIGHT)) to_chat(usr, "The bolt lights wire is cut - The door bolt lights are permanently disabled.") - else if (!activate && src.lights) - lights = 0 - to_chat(usr, "The door bolt lights have been disabled.") - else if (activate && !src.lights) - lights = 1 - to_chat(usr, "The door bolt lights have been enabled.") + return + lights = !lights + update_icon() + . = TRUE + if("safe-toggle") + set_safeties(!safe, 1) + . = TRUE + if("speed-toggle") + if(wires.is_cut(WIRE_SPEED)) + to_chat(usr, "The timing wire is cut - Cannot alter timing.") + return + normalspeed = !normalspeed + . = TRUE + if("open-close") + user_toggle_open(usr) + . = TRUE update_icon() return 1 +/obj/machinery/door/airlock/proc/user_allowed(mob/user) + var/allowed = (issilicon(user) && canAIControl(user)) + if(!allowed && isobserver(user)) + var/mob/observer/dead/D = user + if(D.can_admin_interact()) + allowed = TRUE + return allowed + +/obj/machinery/door/airlock/proc/toggle_bolt(mob/user) + if(!user_allowed(user)) + return + if(wires.is_cut(WIRE_DOOR_BOLTS)) + to_chat(user, "The door bolt drop wire is cut - you can't toggle the door bolts.") + return + if(locked) + if(!arePowerSystemsOn()) + to_chat(user, "The door has no power - you can't raise the door bolts.") + else + unlock() + to_chat(user, "The door bolts have been raised.") + // log_combat(user, src, "unbolted") + else + lock() + to_chat(user, "The door bolts have been dropped.") + // log_combat(user, src, "bolted") + +/obj/machinery/door/airlock/proc/user_toggle_open(mob/user) + if(!user_allowed(user)) + return + if(welded) + to_chat(user, text("The airlock has been welded shut!")) + else if(locked) + to_chat(user, text("The door bolts are down!")) + else if(!density) + close() + else + open() + /obj/machinery/door/airlock/proc/can_remove_electronics() return src.p_open && (operating < 0 || (!operating && welded && !src.arePowerSystemsOn() && density && (!src.locked || (stat & BROKEN)))) diff --git a/code/game/machinery/embedded_controller/airlock_controllers.dm b/code/game/machinery/embedded_controller/airlock_controllers.dm index b15d5afd97..262ffacf41 100644 --- a/code/game/machinery/embedded_controller/airlock_controllers.dm +++ b/code/game/machinery/embedded_controller/airlock_controllers.dm @@ -14,6 +14,7 @@ var/tag_secure = 0 var/list/dummy_terminals = list() var/cycle_to_external_air = 0 + valid_actions = list("cycle_ext", "cycle_int", "force_ext", "force_int", "abort", "purge", "secure") /obj/machinery/embedded_controller/radio/airlock/Destroy() // TODO - Leshana - Implement dummy terminals @@ -23,90 +24,42 @@ //dummy_terminals.Cut() return ..() -/obj/machinery/embedded_controller/radio/airlock/CanUseTopic(var/mob/user) +/obj/machinery/embedded_controller/radio/airlock/tgui_status(mob/user, datum/tgui_state/state) + . = ..() if(!allowed(user)) - return min(STATUS_UPDATE, ..()) - else - return ..() + return min(STATUS_UPDATE, .) //Advanced airlock controller for when you want a more versatile airlock controller - useful for turning simple access control rooms into airlocks /obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller name = "Advanced Airlock Controller" -/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data = list( +/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/tgui_data(mob/user) + . = list( "chamber_pressure" = round(program.memory["chamber_sensor_pressure"]), "external_pressure" = round(program.memory["external_sensor_pressure"]), "internal_pressure" = round(program.memory["internal_sensor_pressure"]), "processing" = program.memory["processing"], "purge" = program.memory["purge"], - "secure" = program.memory["secure"] + "secure" = program.memory["secure"], + "internalTemplateName" = "AirlockConsoleAdvanced", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "advanced_airlock_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/Topic(href, href_list) - if((. = ..())) - return - - switch(href_list["command"]) //anti-HTML-hacking checks - if("cycle_ext", "cycle_int", "force_ext", "force_int", "abort", "purge", "secure") - program.receive_user_command(href_list["command"]) - - return 1 //Airlock controller for airlock control - most airlocks on the station use this /obj/machinery/embedded_controller/radio/airlock/airlock_controller name = "Airlock Controller" tag_secure = 1 + valid_actions = list("cycle_ext", "cycle_int", "force_ext", "force_int", "abort") -/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data = list( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller/tgui_data(mob/user) + . = list( "chamber_pressure" = round(program.memory["chamber_sensor_pressure"]), "exterior_status" = program.memory["exterior_status"], "interior_status" = program.memory["interior_status"], "processing" = program.memory["processing"], + "internalTemplateName" = "AirlockConsoleSimple", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "simple_airlock_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/airlock/airlock_controller/Topic(href, href_list) - if((. = ..())) - return - - var/clean = 0 - switch(href_list["command"]) //anti-HTML-hacking checks - if("cycle_ext") - clean = 1 - if("cycle_int") - clean = 1 - if("force_ext") - clean = 1 - if("force_int") - clean = 1 - if("abort") - clean = 1 - - if(clean) - program.receive_user_command(href_list["command"]) - - return 1 - //Access controller for door control - used in virology and the like /obj/machinery/embedded_controller/radio/airlock/access_controller icon = 'icons/obj/airlock_machines.dmi' @@ -114,6 +67,7 @@ name = "Access Controller" tag_secure = 1 + valid_actions = list("cycle_ext_door", "cycle_int_door", "force_ext", "force_int") /obj/machinery/embedded_controller/radio/airlock/access_controller/update_icon() @@ -125,40 +79,10 @@ else icon_state = "access_control_off" -/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data = list( +/obj/machinery/embedded_controller/radio/airlock/access_controller/tgui_data(mob/user) + . = list( "exterior_status" = program.memory["exterior_status"], "interior_status" = program.memory["interior_status"], - "processing" = program.memory["processing"] + "processing" = program.memory["processing"], + "internalTemplateName" = "DoorAccessConsole", ) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "door_access_console.tmpl", name, 330, 220) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/airlock/access_controller/Topic(href, href_list) - if((. = ..())) - return - - var/clean = 0 - switch(href_list["command"]) //anti-HTML-hacking checks - if("cycle_ext_door") - clean = 1 - if("cycle_int_door") - clean = 1 - if("force_ext") - if(program.memory["interior_status"]["state"] == "closed") - clean = 1 - if("force_int") - if(program.memory["exterior_status"]["state"] == "closed") - clean = 1 - - if(clean) - program.receive_user_command(href_list["command"]) - - return 1 \ No newline at end of file diff --git a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm index d2f9a410a2..ef6367758f 100644 --- a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm +++ b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm @@ -1,4 +1,5 @@ // Provides remote access to a controller (since they must be unique). +// TGUITODO: Actually make these weird things work... well, as much as possible. /obj/machinery/dummy_airlock_controller name = "airlock control terminal" icon = 'icons/obj/airlock_machines.dmi' diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller.dm b/code/game/machinery/embedded_controller/airlock_docking_controller.dm index 4d5048ad6d..080fa7d357 100644 --- a/code/game/machinery/embedded_controller/airlock_docking_controller.dm +++ b/code/game/machinery/embedded_controller/airlock_docking_controller.dm @@ -13,6 +13,7 @@ var/datum/computer/file/embedded_program/docking/airlock/docking_program var/display_name // For mappers to override docking_program.display_name (how would it show up on docking monitoring program) tag_secure = 1 + valid_actions = list("cycle_ext", "cycle_int", "force_ext", "force_int", "abort", "toggle_override") /obj/machinery/embedded_controller/radio/airlock/docking_port/Initialize() . = ..() @@ -34,12 +35,11 @@ else ..() -/obj/machinery/embedded_controller/radio/airlock/docking_port/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/embedded_controller/radio/airlock/docking_port/tgui_data(mob/user) var/datum/computer/file/embedded_program/docking/airlock/docking_program = program var/datum/computer/file/embedded_program/airlock/docking/airlock_program = docking_program.airlock_program - data = list( + . = list( "chamber_pressure" = round(airlock_program.memory["chamber_sensor_pressure"]), "exterior_status" = airlock_program.memory["exterior_status"], "interior_status" = airlock_program.memory["interior_status"], @@ -48,49 +48,16 @@ "airlock_disabled" = !(docking_program.undocked() || docking_program.override_enabled), "override_enabled" = docking_program.override_enabled, "docking_codes" = docking_program.docking_codes, - "name" = docking_program.get_name() + "name" = docking_program.get_name(), + "internalTemplateName" = "AirlockConsoleDocking", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "docking_airlock_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/airlock/docking_port/Topic(href, href_list) - if((. = ..())) - return - - var/clean = 0 - switch(href_list["command"]) //anti-HTML-hacking checks - if("cycle_ext") - clean = 1 - if("cycle_int") - clean = 1 - if("force_ext") - clean = 1 - if("force_int") - clean = 1 - if("abort") - clean = 1 - if("toggle_override") - clean = 1 - - if(clean) - program.receive_user_command(href_list["command"]) - - return 1 - - /////////////////////////////////////////////////////////////////////////////// //A docking controller for an airlock based docking port // /datum/computer/file/embedded_program/docking/airlock var/datum/computer/file/embedded_program/airlock/docking/airlock_program - /datum/computer/file/embedded_program/docking/airlock/New(var/obj/machinery/embedded_controller/M, var/datum/computer/file/embedded_program/airlock/docking/A) ..(M) airlock_program = A diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm index 55182aaaa6..b153437ca6 100644 --- a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm +++ b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm @@ -15,9 +15,7 @@ for (var/i = 1; i <= tags.len; i++) child_names[tags[i]] = names[i] - -/obj/machinery/embedded_controller/radio/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/embedded_controller/radio/docking_port_multi/tgui_data(mob/user) var/datum/computer/file/embedded_program/docking/multi/docking_program = program // Cast to proper type var/list/airlocks[child_names.len] @@ -25,23 +23,14 @@ for (var/child_tag in child_names) airlocks[i++] = list("name"=child_names[child_tag], "override_enabled"=(docking_program.children_override[child_tag] == "enabled")) - data = list( + . = list( "docking_status" = docking_program.get_docking_status(), "airlocks" = airlocks, + "internalTemplateName" = "DockingConsoleMulti", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "multi_docking_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/docking_port_multi/Topic(href, href_list) - return 1 // Apparently we swallow all input (this is corrected legacy code) - - +/obj/machinery/embedded_controller/radio/docking_port_multi/tgui_act(action, params) + return // Apparently we swallow all input (this is corrected legacy code) //a docking port based on an airlock // This is the actual controller that will be commanded by the master defined above @@ -50,12 +39,13 @@ program = /datum/computer/file/embedded_program/airlock/multi_docking var/master_tag //for mapping tag_secure = 1 + valid_actions = list("cycle_ext", "cycle_int", "force_ext", "force_int", "abort", "toggle_override") + -/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/tgui_data(mob/user) var/datum/computer/file/embedded_program/airlock/multi_docking/airlock_program = program // Cast to proper type - data = list( + . = list( "chamber_pressure" = round(airlock_program.memory["chamber_sensor_pressure"]), "exterior_status" = airlock_program.memory["exterior_status"], "interior_status" = airlock_program.memory["interior_status"], @@ -63,42 +53,9 @@ "docking_status" = airlock_program.master_status, "airlock_disabled" = (airlock_program.docking_enabled && !airlock_program.override_enabled), "override_enabled" = airlock_program.override_enabled, + "internalTemplateName" = "AirlockConsoleDocking", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "docking_airlock_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/Topic(href, href_list) - if((. = ..())) - return - - var/clean = 0 - switch(href_list["command"]) //anti-HTML-hacking checks - if("cycle_ext") - clean = 1 - if("cycle_int") - clean = 1 - if("force_ext") - clean = 1 - if("force_int") - clean = 1 - if("abort") - clean = 1 - if("toggle_override") - clean = 1 - - if(clean) - program.receive_user_command(href_list["command"]) - - return 1 - - - /*** DEBUG VERBS *** /datum/computer/file/embedded_program/docking/multi/proc/print_state() diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm index 714d27d560..58db9782da 100644 --- a/code/game/machinery/embedded_controller/embedded_controller_base.dm +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -4,6 +4,7 @@ use_power = USE_POWER_IDLE idle_power_usage = 10 var/datum/computer/file/embedded_program/program //the currently executing program + var/list/valid_actions = list() var/on = 1 /obj/machinery/embedded_controller/Initialize() @@ -24,18 +25,19 @@ if(program) program.receive_signal(signal, receive_method, receive_param) - //spawn(5) program.process() //no, program.process sends some signals and machines respond and we here again and we lag -rastaf0 -/obj/machinery/embedded_controller/Topic(href, href_list) - if((. = ..())) - return +/obj/machinery/embedded_controller/Topic() + . = ..() + stack_trace("WARNING: Embedded controller [src] ([type]) had Topic() called unexpectedly. Please report this.") + +/obj/machinery/embedded_controller/tgui_act(action, params) + if(..()) + return TRUE + if(LAZYLEN(valid_actions)) + if(action in valid_actions) + program.receive_user_command(action) if(usr) - usr.set_machine(src) - src.add_fingerprint(usr) - // We would now pass it to the program, except that some of our embedded controller types want to block certain commands. - // Until/unless that is refactored differently, we rely on subtypes to pass it on. - //if(program) - // return program.receive_user_command(href_list["command"]) + add_fingerprint(usr) /obj/machinery/embedded_controller/process() if(program) @@ -44,19 +46,23 @@ update_icon() /obj/machinery/embedded_controller/attack_ai(mob/user as mob) - src.ui_interact(user) + tgui_interact(user) /obj/machinery/embedded_controller/attack_hand(mob/user as mob) - if(!user.IsAdvancedToolUser()) return 0 - src.ui_interact(user) + tgui_interact(user) + +/obj/machinery/embedded_controller/tgui_interact(mob/user, datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "EmbeddedController", src) + ui.open() // // Embedded controller with a radio! (Most things (All things?) use this) // - /obj/machinery/embedded_controller/radio icon = 'icons/obj/airlock_machines.dmi' icon_state = "airlock_control_standby" diff --git a/code/game/machinery/embedded_controller/simple_docking_controller.dm b/code/game/machinery/embedded_controller/simple_docking_controller.dm index d2e04a3330..df94c21d5c 100644 --- a/code/game/machinery/embedded_controller/simple_docking_controller.dm +++ b/code/game/machinery/embedded_controller/simple_docking_controller.dm @@ -3,42 +3,18 @@ name = "docking hatch controller" program = /datum/computer/file/embedded_program/docking/simple var/tag_door + valid_actions = list("force_door", "toggle_override") -/obj/machinery/embedded_controller/radio/simple_docking_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/embedded_controller/radio/simple_docking_controller/tgui_data(mob/user) var/datum/computer/file/embedded_program/docking/simple/docking_program = program // Cast to proper type - data = list( + . = list( "docking_status" = docking_program.get_docking_status(), "override_enabled" = docking_program.override_enabled, - "door_state" = docking_program.memory["door_status"]["state"], - "door_lock" = docking_program.memory["door_status"]["lock"], + "exterior_status" = docking_program.memory["door_status"], + "internalTemplateName" = "DockingConsoleSimple", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "simple_docking_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/simple_docking_controller/Topic(href, href_list) - if((. = ..())) - return - - var/clean = 0 - switch(href_list["command"]) //anti-HTML-hacking checks - if("force_door") - clean = 1 - if("toggle_override") - clean = 1 - - if(clean) - program.receive_user_command(href_list["command"]) - - return - //A docking controller program for a simple door based docking port /datum/computer/file/embedded_program/docking/simple var/tag_door diff --git a/code/game/machinery/exonet_node.dm b/code/game/machinery/exonet_node.dm index b9b95e103c..a8f6a38734 100644 --- a/code/game/machinery/exonet_node.dm +++ b/code/game/machinery/exonet_node.dm @@ -94,17 +94,25 @@ // Proc: attack_hand() // Parameters: 1 (user - the person clicking on the machine) -// Description: Opens the NanoUI interface with ui_interact() +// Description: Opens the TGUI interface with tgui_interact() /obj/machinery/exonet_node/attack_hand(mob/user) - ui_interact(user) + tgui_interact(user) -// Proc: ui_interact() -// Parameters: 4 (standard NanoUI arguments) +// Proc: tgui_interact() +// Parameters: 2 (user - person interacting with the UI, ui - the UI itself, in a refresh) +// Description: Handles opening the TGUI interface +/obj/machinery/exonet_node/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ExonetNode", src) + ui.open() + +// Proc: tgui_data() +// Parameters: 1 (user - the person using the interface) // Description: Allows the user to turn the machine on or off, or open or close certain 'ports' for things like external PDA messages, newscasters, etc. -/obj/machinery/exonet_node/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/exonet_node/tgui_data(mob/user) // this is the data which will be sent to the ui - var/data[0] - + var/list/data = list() data["on"] = toggle ? 1 : 0 data["allowPDAs"] = allow_external_PDAs @@ -112,53 +120,46 @@ data["allowNewscasters"] = allow_external_newscasters data["logs"] = logs + return data - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "exonet_node.tmpl", "Exonet Node #157", 400, 400) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) - -// Proc: Topic() -// Parameters: 2 (standard Topic arguments) -// Description: Responds to button presses on the NanoUI interface. -/obj/machinery/exonet_node/Topic(href, href_list) +// Proc: tgui_act() +// Parameters: 2 (standard tgui_act arguments) +// Description: Responds to button presses on the TGUI interface. +/obj/machinery/exonet_node/tgui_act(action, params) if(..()) - return 1 - if(href_list["toggle_power"]) - toggle = !toggle - update_power() - if(!toggle) - var/msg = "[usr.client.key] ([usr]) has turned [src] off, at [x],[y],[z]." - message_admins(msg) - log_game(msg) + return TRUE - if(href_list["toggle_PDA_port"]) - allow_external_PDAs = !allow_external_PDAs + switch(action) + if("toggle_power") + . = TRUE + toggle = !toggle + update_power() + if(!toggle) + var/msg = "[usr.client.key] ([usr]) has turned [src] off, at [x],[y],[z]." + message_admins(msg) + log_game(msg) - if(href_list["toggle_communicator_port"]) - allow_external_communicators = !allow_external_communicators - if(!allow_external_communicators) - var/msg = "[usr.client.key] ([usr]) has turned [src]'s communicator port off, at [x],[y],[z]." - message_admins(msg) - log_game(msg) + if("toggle_PDA_port") + . = TRUE + allow_external_PDAs = !allow_external_PDAs - if(href_list["toggle_newscaster_port"]) - allow_external_newscasters = !allow_external_newscasters - if(!allow_external_newscasters) - var/msg = "[usr.client.key] ([usr]) has turned [src]'s newscaster port off, at [x],[y],[z]." - message_admins(msg) - log_game(msg) + if("toggle_communicator_port") + . = TRUE + allow_external_communicators = !allow_external_communicators + if(!allow_external_communicators) + var/msg = "[usr.client.key] ([usr]) has turned [src]'s communicator port off, at [x],[y],[z]." + message_admins(msg) + log_game(msg) + + if("toggle_newscaster_port") + . = TRUE + allow_external_newscasters = !allow_external_newscasters + if(!allow_external_newscasters) + var/msg = "[usr.client.key] ([usr]) has turned [src]'s newscaster port off, at [x],[y],[z]." + message_admins(msg) + log_game(msg) update_icon() - SSnanoui.update_uis(src) add_fingerprint(usr) // Proc: get_exonet_node() diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm index 388b834e82..3ed93f79b3 100644 --- a/code/game/machinery/fire_alarm.dm +++ b/code/game/machinery/fire_alarm.dm @@ -27,6 +27,10 @@ FIRE ALARM /obj/machinery/firealarm/alarms_hidden alarms_hidden = TRUE +/obj/machinery/firealarm/examine() + . = ..() + . += "Current security level: [seclevel]" + /obj/machinery/firealarm/Initialize() . = ..() if(z in using_map.contact_levels) @@ -127,81 +131,24 @@ FIRE ALARM if(user.stat || stat & (NOPOWER | BROKEN)) return - user.set_machine(src) - var/area/A = src.loc - var/d1 - var/d2 - if(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon)) - A = A.loc - - if(A.fire) - d1 = text("Reset - Lockdown", src) - else - d1 = text("Alarm - Lockdown", src) - if(timing) - d2 = text("Stop Time Lock", src) - else - d2 = text("Initiate Time Lock", src) - var/second = round(time) % 60 - var/minute = (round(time) - second) / 60 - var/dat = "Fire alarm [d1]\n
The current alert level is: [get_security_level()]

\nTimer System: [d2]
\nTime Left: [(minute ? "[minute]:" : null)][second] - - + +\n
" - user << browse(dat, "window=firealarm") - onclose(user, "firealarm") + add_fingerprint(user) + var/area/A = get_area(src) + if(A.fire) + reset(user) else - A = A.loc - if(A.fire) - d1 = text("[]", src, stars("Reset - Lockdown")) - else - d1 = text("[]", src, stars("Alarm - Lockdown")) - if(timing) - d2 = text("[]", src, stars("Stop Time Lock")) - else - d2 = text("[]", src, stars("Initiate Time Lock")) - var/second = round(time) % 60 - var/minute = (round(time) - second) / 60 - var/dat = "[stars("Fire alarm")] [d1]\n
The current alert level is: [stars(get_security_level())]

\nTimer System: [d2]
\nTime Left: [(minute ? text("[]:", minute) : null)][second] - - + +\n
" - user << browse(dat, "window=firealarm") - onclose(user, "firealarm") - return + alarm(0, user) -/obj/machinery/firealarm/Topic(href, href_list) - ..() - if(usr.stat || stat & (BROKEN | NOPOWER)) - return - - if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - if(href_list["reset"]) - reset() - else if(href_list["alarm"]) - alarm() - else if(href_list["time"]) - timing = text2num(href_list["time"]) - last_process = world.timeofday - START_PROCESSING(SSobj, src) - else if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 120) - - updateUsrDialog() - - add_fingerprint(usr) - else - usr << browse(null, "window=firealarm") - return - return - -/obj/machinery/firealarm/proc/reset() +/obj/machinery/firealarm/proc/reset(mob/user) if(!(working)) return var/area/area = get_area(src) for(var/obj/machinery/firealarm/FA in area) fire_alarm.clearAlarm(src.loc, FA) update_icon() - return + if(user) + log_game("[user] reset a fire alarm at [COORD(src)]") -/obj/machinery/firealarm/proc/alarm(var/duration = 0) +/obj/machinery/firealarm/proc/alarm(var/duration = 0, mob/user) if(!(working)) return var/area/area = get_area(src) @@ -209,7 +156,8 @@ FIRE ALARM fire_alarm.triggerAlarm(loc, FA, duration, hidden = alarms_hidden) update_icon() playsound(src, 'sound/machines/airalarm.ogg', 25, 0, 4) - return + if(user) + log_game("[user] triggered a fire alarm at [COORD(src)]") /obj/machinery/firealarm/proc/set_security_level(var/newlevel) if(seclevel != newlevel) diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm index 4c4d3ce914..2e728775da 100644 --- a/code/game/machinery/pipe/pipe_dispenser.dm +++ b/code/game/machinery/pipe/pipe_dispenser.dm @@ -15,69 +15,94 @@ "Fuel" = PIPING_LAYER_FUEL, "Aux" = PIPING_LAYER_AUX ) + var/disposals = FALSE // TODO - Its about time to make this NanoUI don't we think? /obj/machinery/pipedispenser/attack_hand(var/mob/user as mob) if((. = ..())) return - src.interact(user) + tgui_interact(user) -/obj/machinery/pipedispenser/interact(mob/user) - user.set_machine(src) +/obj/machinery/pipedispenser/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/pipes), + ) - var/list/lines = list() - for(var/category in atmos_pipe_recipes) - lines += "[category]:
" - if(category == "Pipes") - for(var/pipename in pipe_layers) - var/pipelayer = pipe_layers[pipename] - lines += "[pipename] " - lines += "
" - for(var/datum/pipe_recipe/PI in atmos_pipe_recipes[category]) - lines += PI.Render(src) - var/dat = lines.Join() - var/datum/browser/popup = new(user, "pipedispenser", name, 300, 800, src) - popup.set_content("[dat]") - popup.open() - return +/obj/machinery/pipedispenser/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PipeDispenser", name) + ui.open() -/obj/machinery/pipedispenser/Topic(href, href_list) +/obj/machinery/pipedispenser/tgui_data(mob/user) + var/list/data = list( + "disposals" = disposals, + "p_layer" = p_layer, + "pipe_layers" = pipe_layers, + ) + + var/list/recipes + if(disposals) + recipes = GLOB.disposal_pipe_recipes + else + recipes = GLOB.atmos_pipe_recipes + + for(var/c in recipes) + var/list/cat = recipes[c] + var/list/r = list() + for(var/i in 1 to cat.len) + var/datum/pipe_recipe/info = cat[i] + r += list(list("pipe_name" = info.name, "pipe_index" = i)) + data["categories"] += list(list("cat_name" = c, "recipes" = r)) + + return data + +/obj/machinery/pipedispenser/tgui_act(action, params) if(..()) - return + return TRUE if(unwrenched || !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=pipedispenser") - usr.unset_machine(src) - return - usr.set_machine(src) - src.add_fingerprint(usr) - if(href_list["setlayer"]) - var/new_pipe_layer = text2num(href_list["setlayer"]) - if(isnum(new_pipe_layer)) - p_layer = new_pipe_layer - updateDialog() - else if(href_list["makepipe"]) - if(!wait) - var/obj/machinery/atmospherics/p_type = text2path(href_list["makepipe"]) - var/p_dir = text2num(href_list["dir"]) - var/pi_type = initial(p_type.construction_type) - var/obj/item/pipe/P = new pi_type(src.loc, p_type, p_dir) - P.setPipingLayer(p_layer) - P.add_fingerprint(usr) - wait = 1 - spawn(10) - wait = 0 - else if(href_list["makemeter"]) - if(!wait) - new /obj/item/pipe_meter(/*usr.loc*/ src.loc) - wait = 1 - spawn(15) - wait = 0 - return + return TRUE + + . = TRUE + switch(action) + if("p_layer") + p_layer = text2num(params["p_layer"]) + if("dispense_pipe") + if(!wait) + var/list/recipes + if(disposals) + recipes = GLOB.disposal_pipe_recipes + else + recipes = GLOB.atmos_pipe_recipes + + var/datum/pipe_recipe/recipe = recipes[params["category"]][text2num(params["pipe_type"])] + + var/obj/created_object = null + if(istype(recipe, /datum/pipe_recipe/pipe)) + var/datum/pipe_recipe/pipe/R = recipe + created_object = new R.construction_type(loc, recipe.pipe_type, NORTH) + var/obj/item/pipe/P = created_object + P.setPipingLayer(p_layer) + else if(istype(recipe, /datum/pipe_recipe/disposal)) + var/datum/pipe_recipe/disposal/D = recipe + var/obj/structure/disposalconstruct/C = new(loc, D.pipe_type, NORTH, 0, D.subtype ? D.subtype : 0) + C.update() + created_object = C + else if(istype(recipe, /datum/pipe_recipe/meter)) + created_object = new recipe.pipe_type(loc) + else + log_runtime(EXCEPTION("Warning: [usr] attempted to spawn pipe recipe type by params [json_encode(params)] ([recipe] [recipe?.type]), but it was not allowed by this machine ([src] [type])")) + return + + created_object.add_fingerprint(usr) + wait = TRUE + VARSET_IN(src, wait, FALSE, 15) + /obj/machinery/pipedispenser/attackby(var/obj/item/W as obj, var/mob/user as mob) src.add_fingerprint(usr) if (istype(W, /obj/item/pipe) || istype(W, /obj/item/pipe_meter)) - to_chat(usr, "You put [W] back to [src].") + to_chat(usr, "You put [W] back in [src].") user.drop_item() qdel(W) return @@ -117,15 +142,7 @@ icon_state = "pipe_d" density = 1 anchored = 1.0 - -/* -//Allow you to push disposal pipes into it (for those with density 1) -/obj/machinery/pipedispenser/disposal/Crossed(var/obj/structure/disposalconstruct/pipe as obj) - if(istype(pipe) && !pipe.anchored) - qdel(pipe) - -Nah -*/ + disposals = TRUE //Allow you to drag-drop disposal pipes into it /obj/machinery/pipedispenser/disposal/MouseDrop_T(var/obj/structure/disposalconstruct/pipe as obj, mob/usr as mob) @@ -138,43 +155,9 @@ Nah if (pipe.anchored) return + to_chat(usr, "You shove [pipe] back in [src].") qdel(pipe) -/obj/machinery/pipedispenser/disposal/interact(mob/user) - user.set_machine(src) - - var/list/lines = list() - for(var/category in disposal_pipe_recipes) - lines += "[category]:
" - for(var/datum/pipe_recipe/PI in disposal_pipe_recipes[category]) - lines += PI.Render(src) - var/dat = lines.Join() - var/datum/browser/popup = new(user, "pipedispenser", name, 300, 500, src) - popup.set_content("[dat]") - popup.open() - return - -/obj/machinery/pipedispenser/disposal/Topic(href, href_list) - if(href_list["makepipe"] || href_list["setlayer"] || href_list["makemeter"]) // Asking the disposal machine to do atmos stuff? - return // That's a no no. - if((. = ..())) - return - if(href_list["dmake"]) - if(unwrenched || !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=pipedispenser") - return - if(!wait) - var/ptype = text2num(href_list["dmake"]) - var/pdir = (href_list["dir"] ? text2num(href_list["dir"]) : NORTH) - var/psub = (href_list["sort"] ? text2num(href_list["sort"]) : 0) - var/obj/structure/disposalconstruct/C = new (src.loc, ptype, pdir, 0, psub) - - C.add_fingerprint(usr) - C.update() - wait = 1 - VARSET_IN(src, wait, FALSE, 15) - return - // adding a pipe dispensers that spawn unhooked from the ground /obj/machinery/pipedispenser/orderable anchored = 0 diff --git a/code/game/machinery/pipe/pipe_recipes.dm b/code/game/machinery/pipe/pipe_recipes.dm index 14dbfc2603..e5db17f4b1 100644 --- a/code/game/machinery/pipe/pipe_recipes.dm +++ b/code/game/machinery/pipe/pipe_recipes.dm @@ -2,75 +2,69 @@ // Recipies for Pipe Dispenser and (someday) the RPD // -var/global/list/atmos_pipe_recipes = null -var/global/list/disposal_pipe_recipes = null -var/global/list/all_pipe_recipes = null // VOREStation Add +GLOBAL_LIST_INIT(atmos_pipe_recipes, list( + "Pipes" = list( + new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple), + new /datum/pipe_recipe/pipe("Manifold", /obj/machinery/atmospherics/pipe/manifold), + new /datum/pipe_recipe/pipe("Manual Valve", /obj/machinery/atmospherics/valve), + new /datum/pipe_recipe/pipe("Digital Valve", /obj/machinery/atmospherics/valve/digital), + new /datum/pipe_recipe/pipe("Pipe cap", /obj/machinery/atmospherics/pipe/cap), + new /datum/pipe_recipe/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/manifold4w), + new /datum/pipe_recipe/pipe("Manual T-Valve", /obj/machinery/atmospherics/tvalve), + new /datum/pipe_recipe/pipe("Digital T-Valve", /obj/machinery/atmospherics/tvalve/digital), + new /datum/pipe_recipe/pipe("Upward Pipe", /obj/machinery/atmospherics/pipe/zpipe/up), + new /datum/pipe_recipe/pipe("Downward Pipe", /obj/machinery/atmospherics/pipe/zpipe/down), + new /datum/pipe_recipe/pipe("Universal Pipe Adaptor",/obj/machinery/atmospherics/pipe/simple/visible/universal), + ), + "Devices" = list( + new /datum/pipe_recipe/pipe("Connector", /obj/machinery/atmospherics/portables_connector), + new /datum/pipe_recipe/pipe("Unary Vent", /obj/machinery/atmospherics/unary/vent_pump), + new /datum/pipe_recipe/pipe("Aux Vent", /obj/machinery/atmospherics/unary/vent_pump/aux), + new /datum/pipe_recipe/pipe("Passive Vent", /obj/machinery/atmospherics/pipe/vent), + new /datum/pipe_recipe/pipe("Injector", /obj/machinery/atmospherics/unary/outlet_injector), + new /datum/pipe_recipe/pipe("Gas Pump", /obj/machinery/atmospherics/binary/pump), + new /datum/pipe_recipe/pipe("Fuel Pump", /obj/machinery/atmospherics/binary/pump/fuel), + new /datum/pipe_recipe/pipe("Aux Pump", /obj/machinery/atmospherics/binary/pump/aux), + new /datum/pipe_recipe/pipe("Pressure Regulator", /obj/machinery/atmospherics/binary/passive_gate), + new /datum/pipe_recipe/pipe("High Power Gas Pump", /obj/machinery/atmospherics/binary/pump/high_power), + new /datum/pipe_recipe/pipe("Automatic Shutoff Valve",/obj/machinery/atmospherics/valve/shutoff), + new /datum/pipe_recipe/pipe("Scrubber", /obj/machinery/atmospherics/unary/vent_scrubber), + new /datum/pipe_recipe/meter("Meter"), + new /datum/pipe_recipe/pipe("Gas Filter", /obj/machinery/atmospherics/trinary/atmos_filter), + new /datum/pipe_recipe/pipe("Gas Mixer", /obj/machinery/atmospherics/trinary/mixer), + new /datum/pipe_recipe/pipe("Gas Mixer 'T'", /obj/machinery/atmospherics/trinary/mixer/t_mixer), + new /datum/pipe_recipe/pipe("Omni Gas Mixer", /obj/machinery/atmospherics/omni/mixer), + new /datum/pipe_recipe/pipe("Omni Gas Filter", /obj/machinery/atmospherics/omni/atmos_filter), + ), + "Heat Exchange" = list( + new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple/heat_exchanging), + new /datum/pipe_recipe/pipe("Junction", /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction), + new /datum/pipe_recipe/pipe("Heat Exchanger", /obj/machinery/atmospherics/unary/heat_exchanger), + ), + "Insulated pipes" = list( + new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple/insulated), + ) +)) -/hook/startup/proc/init_pipe_recipes() - global.atmos_pipe_recipes = list( - "Pipes" = list( - new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple), - new /datum/pipe_recipe/pipe("Manifold", /obj/machinery/atmospherics/pipe/manifold), - new /datum/pipe_recipe/pipe("Manual Valve", /obj/machinery/atmospherics/valve), - new /datum/pipe_recipe/pipe("Digital Valve", /obj/machinery/atmospherics/valve/digital), - new /datum/pipe_recipe/pipe("Pipe cap", /obj/machinery/atmospherics/pipe/cap), - new /datum/pipe_recipe/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/manifold4w), - new /datum/pipe_recipe/pipe("Manual T-Valve", /obj/machinery/atmospherics/tvalve), - new /datum/pipe_recipe/pipe("Digital T-Valve", /obj/machinery/atmospherics/tvalve/digital), - new /datum/pipe_recipe/pipe("Upward Pipe", /obj/machinery/atmospherics/pipe/zpipe/up), - new /datum/pipe_recipe/pipe("Downward Pipe", /obj/machinery/atmospherics/pipe/zpipe/down), - new /datum/pipe_recipe/pipe("Universal Pipe Adaptor",/obj/machinery/atmospherics/pipe/simple/visible/universal), - ), - "Devices" = list( - new /datum/pipe_recipe/pipe("Connector", /obj/machinery/atmospherics/portables_connector), - new /datum/pipe_recipe/pipe("Unary Vent", /obj/machinery/atmospherics/unary/vent_pump), - new /datum/pipe_recipe/pipe("Aux Vent", /obj/machinery/atmospherics/unary/vent_pump/aux), - new /datum/pipe_recipe/pipe("Passive Vent", /obj/machinery/atmospherics/pipe/vent), - new /datum/pipe_recipe/pipe("Injector", /obj/machinery/atmospherics/unary/outlet_injector), - new /datum/pipe_recipe/pipe("Gas Pump", /obj/machinery/atmospherics/binary/pump), - new /datum/pipe_recipe/pipe("Fuel Pump", /obj/machinery/atmospherics/binary/pump/fuel), - new /datum/pipe_recipe/pipe("Aux Pump", /obj/machinery/atmospherics/binary/pump/aux), - new /datum/pipe_recipe/pipe("Pressure Regulator", /obj/machinery/atmospherics/binary/passive_gate), - new /datum/pipe_recipe/pipe("High Power Gas Pump", /obj/machinery/atmospherics/binary/pump/high_power), - new /datum/pipe_recipe/pipe("Automatic Shutoff Valve",/obj/machinery/atmospherics/valve/shutoff), - new /datum/pipe_recipe/pipe("Scrubber", /obj/machinery/atmospherics/unary/vent_scrubber), - new /datum/pipe_recipe/meter("Meter"), - new /datum/pipe_recipe/pipe("Gas Filter", /obj/machinery/atmospherics/trinary/atmos_filter), - new /datum/pipe_recipe/pipe("Gas Mixer", /obj/machinery/atmospherics/trinary/mixer), - new /datum/pipe_recipe/pipe("Gas Mixer 'T'", /obj/machinery/atmospherics/trinary/mixer/t_mixer), - new /datum/pipe_recipe/pipe("Omni Gas Mixer", /obj/machinery/atmospherics/omni/mixer), - new /datum/pipe_recipe/pipe("Omni Gas Filter", /obj/machinery/atmospherics/omni/atmos_filter), - ), - "Heat Exchange" = list( - new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple/heat_exchanging), - new /datum/pipe_recipe/pipe("Junction", /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction), - new /datum/pipe_recipe/pipe("Heat Exchanger", /obj/machinery/atmospherics/unary/heat_exchanger), - ), - "Insulated pipes" = list( - new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple/insulated), - ) +GLOBAL_LIST_INIT(disposal_pipe_recipes, list( + "Disposal Pipes" = list( + new /datum/pipe_recipe/disposal("Pipe", DISPOSAL_PIPE_STRAIGHT, "conpipe-s", PIPE_STRAIGHT), + new /datum/pipe_recipe/disposal("Bent Pipe", DISPOSAL_PIPE_CORNER, "conpipe-c"), + new /datum/pipe_recipe/disposal("Junction", DISPOSAL_PIPE_JUNCTION, "conpipe-j1", PIPE_TRIN_M), + new /datum/pipe_recipe/disposal("Y-Junction", DISPOSAL_PIPE_JUNCTION_Y, "conpipe-y"), + new /datum/pipe_recipe/disposal("Sort Junction", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_NORMAL), + new /datum/pipe_recipe/disposal("Sort Junction (Wildcard)", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_WILDCARD), + new /datum/pipe_recipe/disposal("Sort Junction (Untagged)", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_UNTAGGED), + new /datum/pipe_recipe/disposal("Tagger", DISPOSAL_PIPE_TAGGER, "pipe-tagger", PIPE_STRAIGHT), + new /datum/pipe_recipe/disposal("Tagger (Partial)", DISPOSAL_PIPE_TAGGER_PARTIAL, "pipe-tagger-partial", PIPE_STRAIGHT), + new /datum/pipe_recipe/disposal("Trunk", DISPOSAL_PIPE_TRUNK, "conpipe-t"), + new /datum/pipe_recipe/disposal("Upwards", DISPOSAL_PIPE_UPWARD, "pipe-u"), + new /datum/pipe_recipe/disposal("Downwards", DISPOSAL_PIPE_DOWNWARD, "pipe-d"), + new /datum/pipe_recipe/disposal("Bin", DISPOSAL_PIPE_BIN, "disposal", PIPE_ONEDIR), + new /datum/pipe_recipe/disposal("Outlet", DISPOSAL_PIPE_OUTLET, "outlet"), + new /datum/pipe_recipe/disposal("Chute", DISPOSAL_PIPE_CHUTE, "intake"), ) - global.disposal_pipe_recipes = list( - "Disposal Pipes" = list( - new /datum/pipe_recipe/disposal("Pipe", DISPOSAL_PIPE_STRAIGHT, "conpipe-s", PIPE_STRAIGHT), - new /datum/pipe_recipe/disposal("Bent Pipe", DISPOSAL_PIPE_CORNER, "conpipe-c"), - new /datum/pipe_recipe/disposal("Junction", DISPOSAL_PIPE_JUNCTION, "conpipe-j1", PIPE_TRIN_M), - new /datum/pipe_recipe/disposal("Y-Junction", DISPOSAL_PIPE_JUNCTION_Y, "conpipe-y"), - new /datum/pipe_recipe/disposal("Sort Junction", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_NORMAL), - new /datum/pipe_recipe/disposal("Sort Junction (Wildcard)", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_WILDCARD), - new /datum/pipe_recipe/disposal("Sort Junction (Untagged)", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_UNTAGGED), - new /datum/pipe_recipe/disposal("Tagger", DISPOSAL_PIPE_TAGGER, "pipe-tagger", PIPE_STRAIGHT), - new /datum/pipe_recipe/disposal("Tagger (Partial)", DISPOSAL_PIPE_TAGGER_PARTIAL, "pipe-tagger-partial", PIPE_STRAIGHT), - new /datum/pipe_recipe/disposal("Trunk", DISPOSAL_PIPE_TRUNK, "conpipe-t"), - new /datum/pipe_recipe/disposal("Upwards", DISPOSAL_PIPE_UPWARD, "pipe-u"), - new /datum/pipe_recipe/disposal("Downwards", DISPOSAL_PIPE_DOWNWARD, "pipe-d"), - new /datum/pipe_recipe/disposal("Bin", DISPOSAL_PIPE_BIN, "disposal", PIPE_ONEDIR), - new /datum/pipe_recipe/disposal("Outlet", DISPOSAL_PIPE_OUTLET, "outlet"), - new /datum/pipe_recipe/disposal("Chute", DISPOSAL_PIPE_CHUTE, "intake"), - ) - ) - global.all_pipe_recipes = disposal_pipe_recipes + atmos_pipe_recipes // VOREStation Add - return TRUE +)) // // New method of handling pipe construction. Instead of numeric constants and a giant switch statement of doom @@ -83,11 +77,52 @@ var/global/list/all_pipe_recipes = null // VOREStation Add var/icon_state = null // This tells the RPD what kind of pipe icon to render for the preview. var/icon_state_m = null // This stores the mirrored version of the regular state (if available). var/dirtype // If using an RPD, this tells more about what previews to show. + var/pipe_type // Render an HTML link to select this pipe type. Returns text. /datum/pipe_recipe/proc/Render(dispenser) return "[name]
" +// Get preview for UIs +/datum/pipe_recipe/proc/get_preview(selected_dir) + var/list/dirs + switch(dirtype) + if(PIPE_STRAIGHT, PIPE_BENDABLE) + dirs = list("[NORTH]" = "Vertical", "[EAST]" = "Horizontal") + if(dirtype == PIPE_BENDABLE) + dirs += list("[NORTHWEST]" = "West to North", "[NORTHEAST]" = "North to East", + "[SOUTHWEST]" = "South to West", "[SOUTHEAST]" = "East to South") + if(PIPE_TRINARY) + dirs = list("[NORTH]" = "West South East", "[SOUTH]" = "East North West", + "[EAST]" = "North West South", "[WEST]" = "South East North") + if(PIPE_TRIN_M) + dirs = list("[NORTH]" = "North East South", "[SOUTHWEST]" = "North West South", + "[NORTHEAST]" = "South East North", "[SOUTH]" = "South West North", + "[WEST]" = "West North East", "[SOUTHEAST]" = "West South East", + "[NORTHWEST]" = "East North West", "[EAST]" = "East South West",) + if(PIPE_DIRECTIONAL) + dirs = list("[NORTH]" = "North", "[SOUTH]" = "South", "[WEST]" = "West", "[EAST]" = "East") + if(PIPE_ONEDIR) + dirs = list("[SOUTH]" = name) + if(PIPE_UNARY_FLIPPABLE) + dirs = list("[NORTH]" = "North", "[EAST]" = "East", "[SOUTH]" = "South", "[WEST]" = "West", + "[NORTHEAST]" = "North Flipped", "[SOUTHEAST]" = "East Flipped", "[SOUTHWEST]" = "South Flipped", "[NORTHWEST]" = "West Flipped") + + + var/list/rows = list() + var/list/row = list("previews" = list()) + var/i = 0 + for(var/dir in dirs) + var/numdir = text2num(dir) + var/flipped = ((dirtype == PIPE_TRIN_M) || (dirtype == PIPE_UNARY_FLIPPABLE)) && (numdir in GLOB.cornerdirs) + row["previews"] += list(list("selected" = (numdir == selected_dir), "dir" = dir2text(numdir), "dir_name" = dirs[dir], "icon_state" = icon_state, "flipped" = flipped)) + if(i++ || dirtype == PIPE_ONEDIR) + rows += list(row) + row = list("previews" = list()) + i = 0 + + return rows + // Parameters for the Topic link returned by Render(). Returns text. /datum/pipe_recipe/proc/Params() return "" @@ -97,7 +132,6 @@ var/global/list/all_pipe_recipes = null // VOREStation Add // /datum/pipe_recipe/pipe var/obj/item/pipe/construction_type // The type PATH to the type of pipe fitting object the recipe makes. - var/obj/machinery/atmospherics/pipe_type // The type PATH of what actual pipe the fitting becomes. var/paintable = FALSE // If TRUE, allow the RPD to paint this pipe. // VOREStation Add /datum/pipe_recipe/pipe/New(var/label, var/obj/machinery/atmospherics/path) @@ -129,6 +163,7 @@ var/global/list/all_pipe_recipes = null // VOREStation Add /datum/pipe_recipe/meter dirtype = PIPE_ONEDIR icon_state = "meter" + pipe_type = /obj/item/pipe_meter /datum/pipe_recipe/meter/New(label) name = label @@ -140,7 +175,6 @@ var/global/list/all_pipe_recipes = null // VOREStation Add // Subtype for disposal pipes // /datum/pipe_recipe/disposal - var/pipe_type // pipe_type is one of the DISPOSAL_PIPE_ ptype constants. var/subtype // subtype is one of the DISPOSAL_SORT_ constants. /datum/pipe_recipe/disposal/New(var/label, var/ptype, var/state, dt=PIPE_DIRECTIONAL, var/sort=0) diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index 77a35d2829..54aac0a5ff 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -11,6 +11,7 @@ var/set_temperature = T0C + 20 //K var/heating_power = 40000 clicksound = "switch" + interact_offline = TRUE /obj/machinery/space_heater/New() ..() @@ -88,75 +89,74 @@ interact(user) /obj/machinery/space_heater/interact(mob/user as mob) - if(panel_open) - - var/dat - dat = "Power cell: " - if(cell) - dat += "Installed
" - else - dat += "Removed
" - - dat += "Power Level: [cell ? round(cell.percent(),1) : 0]%

" - - dat += "Set Temperature: " - - dat += "-" - - dat += " [set_temperature]K ([set_temperature-T0C]°C)" - dat += "+
" - - user.set_machine(src) - user << browse("Space Heater Control Panel[dat]", "window=spaceheater") - onclose(user, "spaceheater") + tgui_interact(user) else on = !on user.visible_message("[user] switches [on ? "on" : "off"] the [src].","You switch [on ? "on" : "off"] the [src].") update_icon() return +/obj/machinery/space_heater/tgui_state(mob/user) + return GLOB.tgui_physical_state -/obj/machinery/space_heater/Topic(href, href_list) - if(usr.stat) - return - if((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) +/obj/machinery/space_heater/tgui_status(mob/user) + if(!panel_open) + return STATUS_CLOSE + return ..() - switch(href_list["op"]) +/obj/machinery/space_heater/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SpaceHeater", name) + ui.open() - if("temp") - var/value = text2num(href_list["val"]) +/obj/machinery/space_heater/tgui_data(mob/user) + var/list/data = list() - // limit to 0-90 degC - set_temperature = dd_range(T0C, T0C + 90, set_temperature + value) + data["cell"] = !!cell + data["power"] = round(cell?.percent(), 1) + data["temp"] = set_temperature + data["minTemp"] = T0C + data["maxTemp"] = T0C + 90 - if("cellremove") - if(panel_open && cell && !usr.get_active_hand()) - usr.visible_message("\The [usr] removes \the [cell] from \the [src].", "You remove \the [cell] from \the [src].") - cell.update_icon() - usr.put_in_hands(cell) - cell.add_fingerprint(usr) - cell = null + return data + +/obj/machinery/space_heater/tgui_act(action, params) + if(..()) + return TRUE + + if(!panel_open) + return FALSE + + switch(action) + if("temp") + // limit to 0-90 degC + set_temperature = clamp(text2num(params["newtemp"]), T0C, T0C + 90) + . = TRUE + + if("cellremove") + if(cell && !usr.get_active_hand()) + usr.visible_message("[usr] removes [cell] from [src].", "You remove [cell] from [src].") + cell.update_icon() + usr.put_in_hands(cell) + cell.add_fingerprint(usr) + cell = null + power_change() + . = TRUE + + + if("cellinstall") + if(!cell) + var/obj/item/weapon/cell/C = usr.get_active_hand() + if(istype(C)) + usr.drop_item() + cell = C + C.loc = src + C.add_fingerprint(usr) power_change() - - - if("cellinstall") - if(panel_open && !cell) - var/obj/item/weapon/cell/C = usr.get_active_hand() - if(istype(C)) - usr.drop_item() - cell = C - C.loc = src - C.add_fingerprint(usr) - power_change() - usr.visible_message("[usr] inserts \the [C] into \the [src].", "You insert \the [C] into \the [src].") - - updateDialog() - else - usr << browse(null, "window=spaceheater") - usr.unset_machine() - return + usr.visible_message("[usr] inserts \the [C] into \the [src].", "You insert \the [C] into \the [src].") + . = TRUE /obj/machinery/space_heater/process() if(on) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 718b71b644..6304820087 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -83,114 +83,93 @@ return return -/obj/machinery/suit_storage_unit/attack_hand(mob/user as mob) - var/dat +/obj/machinery/suit_storage_unit/attack_hand(mob/user) if(..()) return if(stat & NOPOWER) return if(!user.IsAdvancedToolUser()) return 0 - if(panelopen) //The maintenance panel is open. Time for some shady stuff - dat+= "Suit storage unit: Maintenance panel" - dat+= "Maintenance panel controls
" - dat+= "The panel is ridden with controls, button and meters, labeled in strange signs and symbols that
you cannot understand. Probably the manufactoring world's language.
Among other things, a few controls catch your eye.


" - dat+= text("A small dial with a small lambda symbol on it. It's pointing towards a gauge that reads [].
Turn towards []
",(issuperUV ? "15nm" : "185nm"),src,(issuperUV ? "185nm" : "15nm")) - dat+= text("A thick old-style button, with 2 grimy LED lights next to it. The [] LED is on.
Press button",(safetieson? "GREEN" : "RED"),src) - dat+= text("

Close panel", user) - //user << browse(dat, "window=ssu_m_panel;size=400x500") - //onclose(user, "ssu_m_panel") - else if(isUV) //The thing is running its cauterisation cycle. You have to wait. - dat += "Suit storage unit" - dat+= "Unit is cauterising contents with selected UV ray intensity. Please wait.
" - //dat+= "Cycle end in: [cycletimeleft()] seconds. " - //user << browse(dat, "window=ssu_cycling_panel;size=400x500") - //onclose(user, "ssu_cycling_panel") + tgui_interact(user) +/obj/machinery/suit_storage_unit/tgui_state(mob/user) + return GLOB.tgui_notcontained_state + +/obj/machinery/suit_storage_unit/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SuitStorageUnit", name) + ui.open() + +/obj/machinery/suit_storage_unit/tgui_data() + var/list/data = list() + + data["broken"] = isbroken + data["panelopen"] = panelopen + + data["locked"] = islocked + data["open"] = isopen + data["safeties"] = safetieson + data["uv_active"] = isUV + data["uv_super"] = issuperUV + if(HELMET) + data["helmet"] = HELMET.name else - if(!isbroken) - dat+= "Suit storage unit" - dat+= "U-Stor-It Suit Storage Unit, model DS1900
" - dat+= "Welcome to the Unit control panel.

" - dat+= text("Helmet storage compartment: []
",(HELMET ? HELMET.name : "No helmet detected.")) - if(HELMET && isopen) - dat+=text("Dispense helmet
",src) - dat+= text("Suit storage compartment: []
",(SUIT ? SUIT.name : "
No exosuit detected.")) - if(SUIT && isopen) - dat+=text("Dispense suit
",src) - dat+= text("Breathmask storage compartment: []
",(MASK ? MASK.name : "
No breathmask detected.")) - if(MASK && isopen) - dat+=text("Dispense mask
",src) - if(OCCUPANT) - dat+= "
WARNING: Biological entity detected inside the Unit's storage. Please remove.
" - dat+= "Eject extra load" - dat+= text("
Unit is: [] - [] Unit ",(isopen ? "Open" : "Closed"),src,(isopen ? "Close" : "Open")) - if(isopen) - dat+="
" - else - dat+= text(" - *[] Unit*
",src,(islocked ? "Unlock" : "Lock")) - dat+= text("Unit status: []",(islocked? "**LOCKED**
" : "**UNLOCKED**
")) - dat+= text("Start Disinfection cycle
",src) - dat += text("

Close control panel", user) - //user << browse(dat, "window=Suit Storage Unit;size=400x500") - //onclose(user, "Suit Storage Unit") - else //Ohhhh shit it's dirty or broken! Let's inform the guy. - dat+= "Suit storage unit" - dat+= "Unit chamber is too contaminated to continue usage. Please call for a qualified individual to perform maintenance.

" - dat+= text("
Close control panel", user) - //user << browse(dat, "window=suit_storage_unit;size=400x500") - //onclose(user, "suit_storage_unit") + data["helmet"] = null + if(SUIT) + data["suit"] = SUIT.name + else + data["suit"] = null + if(MASK) + data["mask"] = MASK.name + else + data["mask"] = null + data["storage"] = null + if(OCCUPANT) + data["occupied"] = TRUE + else + data["occupied"] = FALSE + return data - user << browse(dat, "window=suit_storage_unit;size=400x500") - onclose(user, "suit_storage_unit") - return +/obj/machinery/suit_storage_unit/tgui_act(action, params) //I fucking HATE this proc + if(..() || isUV || isbroken) + return TRUE - -/obj/machinery/suit_storage_unit/Topic(href, href_list) //I fucking HATE this proc - if(..()) - return - if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) - usr.set_machine(src) - if(href_list["toggleUV"]) - toggleUV(usr) - updateUsrDialog() - update_icon() - if(href_list["togglesafeties"]) - togglesafeties(usr) - updateUsrDialog() - update_icon() - if(href_list["dispense_helmet"]) - dispense_helmet(usr) - updateUsrDialog() - update_icon() - if(href_list["dispense_suit"]) - dispense_suit(usr) - updateUsrDialog() - update_icon() - if(href_list["dispense_mask"]) - dispense_mask(usr) - updateUsrDialog() - update_icon() - if(href_list["toggle_open"]) + switch(action) + if("door") toggle_open(usr) - updateUsrDialog() - update_icon() - if(href_list["toggle_lock"]) - toggle_lock(usr) - updateUsrDialog() - update_icon() - if(href_list["start_UV"]) + . = TRUE + if("dispense") + switch(params["item"]) + if("helmet") + dispense_helmet(usr) + if("mask") + dispense_mask(usr) + if("suit") + dispense_suit(usr) + . = TRUE + if("uv") start_UV(usr) - updateUsrDialog() - update_icon() - if(href_list["eject_guy"]) + . = TRUE + if("lock") + toggle_lock(usr) + . = TRUE + if("eject_guy") eject_occupant(usr) - updateUsrDialog() - update_icon() - /*if(href_list["refresh"]) - updateUsrDialog()*/ + . = TRUE + + // Panel Open stuff + if(!. && panelopen) + switch(action) + if("toggleUV") + toggleUV(usr) + . = TRUE + if("togglesafeties") + togglesafeties(usr) + . = TRUE + + update_icon() add_fingerprint(usr) - return /obj/machinery/suit_storage_unit/proc/toggleUV(mob/user as mob) @@ -847,9 +826,7 @@ return 1 /obj/machinery/suit_cycler/attack_hand(mob/user as mob) - add_fingerprint(user) - if(..() || stat & (BROKEN|NOPOWER)) return @@ -860,116 +837,134 @@ if(shock(user, 100)) return - user.set_machine(src) + tgui_interact(user) - var/dat = "Suit Cycler Interface" +/obj/machinery/suit_cycler/tgui_state(mob/user) + return GLOB.tgui_notcontained_state - if(active) - dat+= "
The [model_text ? "[model_text] " : ""]suit cycler is currently in use. Please wait..." +/obj/machinery/suit_cycler/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SuitCycler", name) + ui.open() - else if(locked) - dat += "
The [model_text ? "[model_text] " : ""]suit cycler is currently locked. Please contact your system administrator." - if(allowed(user)) - dat += "
\[unlock unit\]" +/obj/machinery/suit_cycler/tgui_data(mob/user) + var/list/data = list() + + data["departments"] = departments + data["species"] = species + data["model_text"] = model_text + data["can_repair"] = can_repair + data["userHasAccess"] = allowed(user) + + data["locked"] = locked + data["active"] = active + data["safeties"] = safeties + data["uv_active"] = (active && irradiating > 0) + data["uv_level"] = radiation_level + data["max_uv_level"] = emagged ? 5 : 3 + if(helmet) + data["helmet"] = helmet.name else - dat += "

Suit cycler

" - dat += "Welcome to the [model_text ? "[model_text] " : ""]suit cycler control panel. \[lock unit\]
" + data["helmet"] = null + if(suit) + data["suit"] = suit.name + if(istype(suit) && can_repair) + data["damage"] = suit.damage + else + data["suit"] = null + data["damage"] = null + if(occupant) + data["occupied"] = TRUE + else + data["occupied"] = FALSE - dat += "

Maintenance

" - dat += "Helmet: [helmet ? "\the [helmet]" : "no helmet stored" ]. \[eject\]
" - dat += "Suit: [suit ? "\the [suit]" : "no suit stored" ]. \[eject\]" + return data - if(can_repair && suit && istype(suit)) - dat += "[(suit.damage ? " \[repair\]" : "")]" +/obj/machinery/suit_cycler/tgui_act(action, params) + if(..()) + return TRUE - dat += "
UV decontamination systems: SYSTEM ERROR" : "green'>READY"]
" - dat += "Output level: [radiation_level]
" - dat += "\[select power level\] \[begin decontamination cycle\]

" + switch(action) + if("dispense") + switch(params["item"]) + if("helmet") + helmet.forceMove(get_turf(src)) + helmet = null + if("suit") + suit.forceMove(get_turf(src)) + suit = null + . = TRUE + + if("department") + var/choice = params["department"] + if(choice in departments) + target_department = choice + . = TRUE + + if("species") + var/choice = params["species"] + if(choice in species) + target_species = choice + . = TRUE + + if("radlevel") + radiation_level = clamp(params["radlevel"], 1, emagged ? 5 : 3) + . = TRUE + + if("repair_suit") + if(!suit || !can_repair) + return + active = 1 + spawn(100) + repair_suit() + finished_job() + . = TRUE - dat += "

Customisation

" - dat += "Target product: [target_department], [target_species]." - dat += "
\[apply customisation routine\]


" + if("apply_paintjob") + if(!suit && !helmet) + return + active = 1 + spawn(100) + apply_paintjob() + finished_job() + . = TRUE - if(panel_open) - wires.Interact(user) + if("lock") + if(allowed(usr)) + locked = !locked + to_chat(usr, "You [locked ? "" : "un"]lock \the [src].") + else + to_chat(usr, "Access denied.") + . = TRUE - user << browse(dat, "window=suit_cycler") - onclose(user, "suit_cycler") - return + if("eject_guy") + eject_occupant(usr) + . = TRUE -/obj/machinery/suit_cycler/Topic(href, href_list) - if(href_list["eject_suit"]) - if(!suit) return - suit.loc = get_turf(src) - suit = null - else if(href_list["eject_helmet"]) - if(!helmet) return - helmet.loc = get_turf(src) - helmet = null - else if(href_list["select_department"]) - var/choice = input("Please select the target department paintjob.","Suit cycler",null) as null|anything in departments - if(choice) target_department = choice - else if(href_list["select_species"]) - var/choice = input("Please select the target species configuration.","Suit cycler",null) as null|anything in species - if(choice) target_species = choice - else if(href_list["select_rad_level"]) - var/choices = list(1,2,3) - if(emagged) - choices = list(1,2,3,4,5) - radiation_level = input("Please select the desired radiation level.","Suit cycler",null) as null|anything in choices - else if(href_list["repair_suit"]) + if("uv") + if(safeties && occupant) + to_chat(usr, "The cycler has detected an occupant. Please remove the occupant before commencing the decontamination cycle.") + return - if(!suit || !can_repair) return - active = 1 - spawn(100) - repair_suit() - finished_job() + active = 1 + irradiating = 10 - else if(href_list["apply_paintjob"]) + sleep(10) - if(!suit && !helmet) return - active = 1 - spawn(100) - apply_paintjob() - finished_job() + if(helmet) + if(radiation_level > 2) + helmet.decontaminate() + if(radiation_level > 1) + helmet.clean_blood() - else if(href_list["toggle_safties"]) - safeties = !safeties + if(suit) + if(radiation_level > 2) + suit.decontaminate() + if(radiation_level > 1) + suit.clean_blood() - else if(href_list["toggle_lock"]) - - if(allowed(usr)) - locked = !locked - to_chat(usr, "You [locked ? "" : "un"]lock \the [src].") - else - to_chat(usr, "Access denied.") - - else if(href_list["begin_decontamination"]) - - if(safeties && occupant) - to_chat(usr, "The cycler has detected an occupant. Please remove the occupant before commencing the decontamination cycle.") - return - - active = 1 - irradiating = 10 - updateUsrDialog() - - sleep(10) - - if(helmet) - if(radiation_level > 2) - helmet.decontaminate() - if(radiation_level > 1) - helmet.clean_blood() - - if(suit) - if(radiation_level > 2) - suit.decontaminate() - if(radiation_level > 1) - suit.clean_blood() - - updateUsrDialog() - return + . = TRUE /obj/machinery/suit_cycler/process() diff --git a/code/game/machinery/telecomms/logbrowser.dm b/code/game/machinery/telecomms/logbrowser.dm index 8cd1d8811e..b5dd077efa 100644 --- a/code/game/machinery/telecomms/logbrowser.dm +++ b/code/game/machinery/telecomms/logbrowser.dm @@ -8,187 +8,138 @@ desc = "View communication logs here. Translation not guaranteed." icon_screen = "comm_logs" - var/screen = 0 // the screen number: var/list/servers = list() // the servers located by the computer var/obj/machinery/telecomms/server/SelectedServer circuit = /obj/item/weapon/circuitboard/comm_server var/network = "NULL" // the network to probe - var/temp = "" // temporary feedback messages + var/list/temp = null // temporary feedback messages var/universal_translate = 0 // set to 1 if it can translate nonhuman speech req_access = list(access_tcomsat) - attack_hand(mob/user as mob) - if(stat & (BROKEN|NOPOWER)) - return - user.set_machine(src) - var/dat = "Telecommunication Server Monitor
Telecommunications Server Monitor
" +/obj/machinery/computer/telecomms/server/tgui_data(mob/user) + var/list/data = list() - switch(screen) + data["universal_translate"] = universal_translate + data["network"] = network + data["temp"] = temp + data["servers"] = list() + for(var/obj/machinery/telecomms/T in servers) + data["servers"].Add(list(list( + "id" = T.id, + "name" = T.name, + ))) - // --- Main Menu --- + data["selectedServer"] = null + if(SelectedServer) + data["selectedServer"] = list( + "id" = SelectedServer.id, + "totalTraffic" = SelectedServer.totaltraffic, + "logs" = list() + ) - if(0) - dat += "
[temp]
" - dat += "
Current Network: [network]
" - if(servers.len) - dat += "
Detected Telecommunication Servers:" - dat += "
\[Flush Buffer\]" + var/i = 0 + for(var/c in SelectedServer.log_entries) + i++ + var/datum/comm_log_entry/C = c + + // This is necessary to prevent leaking information to the clientside + var/static/list/acceptable_params = list("uspeech", "intelligible", "message", "name", "race", "job", "timecode") + var/list/parameters = list() + for(var/log_param in acceptable_params) + parameters["[log_param]"] = C.parameters["[log_param]"] - else - dat += "
No servers detected. Scan for servers: \[Scan\]" + data["selectedServer"]["logs"].Add(list(list( + "name" = C.name, + "input_type" = C.input_type, + "id" = i, + "parameters" = parameters, + ))) + return data - // --- Viewing Server --- - - if(1) - dat += "
[temp]
" - dat += "
\[Main Menu\] \[Refresh\]
" - dat += "
Current Network: [network]" - dat += "
Selected Server: [SelectedServer.id]" - - if(SelectedServer.totaltraffic >= 1024) - dat += "
Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes

" - else - dat += "
Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes

" - - dat += "Stored Logs:
    " - - var/i = 0 - for(var/datum/comm_log_entry/C in SelectedServer.log_entries) - i++ - - - // If the log is a speech file - if(C.input_type == "Speech File") - - dat += "
  1. [C.name] \[X\]
    " - - // -- Determine race of orator -- - - var/race = C.parameters["race"] // The actual race of the mob - var/language = C.parameters["language"] // The language spoken, or null/"" - - // -- If the orator is a human, or universal translate is active, OR mob has universal speech on -- - - if(universal_translate || C.parameters["uspeech"] || C.parameters["intelligible"]) - dat += "Data type: [C.input_type]
    " - dat += "Source: [C.parameters["name"]] (Job: [C.parameters["job"]])
    " - dat += "Class: [race]
    " - dat += "Contents: \"[C.parameters["message"]]\"
    " - if(language) - dat += "Language: [language]
    " - - // -- Orator is not human and universal translate not active -- - - else - dat += "Data type: Audio File
    " - dat += "Source: Unidentifiable
    " - dat += "Class: [race]
    " - dat += "Contents: Unintelligble
    " - - dat += "

  2. " - - else if(C.input_type == "Execution Error") - - dat += "
  3. [C.name] \[X\]
    " - dat += "Output: \"[C.parameters["message"]]\"
    " - dat += "

  4. " - - - dat += "
" - - - - user << browse(dat, "window=comm_monitor;size=575x400") - onclose(user, "server_control") - - temp = "" +/obj/machinery/computer/telecomms/server/attack_hand(mob/user) + if(stat & (BROKEN|NOPOWER)) return + tgui_interact(user) +/obj/machinery/computer/telecomms/server/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TelecommsLogBrowser", name) + ui.open() + +/obj/machinery/computer/telecomms/server/tgui_act(action, params) + if(..()) + return TRUE - Topic(href, href_list) - if(..()) - return + add_fingerprint(usr) - - add_fingerprint(usr) - usr.set_machine(src) - - if(href_list["viewserver"]) - screen = 1 + switch(action) + if("view") for(var/obj/machinery/telecomms/T in servers) - if(T.id == href_list["viewserver"]) + if(T.id == params["id"]) SelectedServer = T break + . = TRUE - if(href_list["operation"]) - switch(href_list["operation"]) + if("mainmenu") + SelectedServer = null + . = TRUE - if("release") - servers = list() - screen = 0 + if("release") + servers = list() + SelectedServer = null + . = TRUE - if("mainmenu") - screen = 0 + if("scan") + if(servers.len > 0) + set_temp("FAILED: CANNOT PROBE WHEN BUFFER FULL", "bad") + return TRUE - if("scan") - if(servers.len > 0) - temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" + for(var/obj/machinery/telecomms/server/T in range(25, src)) + if(T.network == network) + servers.Add(T) - else - for(var/obj/machinery/telecomms/server/T in range(25, src)) - if(T.network == network) - servers.Add(T) + if(!servers.len) + set_temp("FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\]", "bad") + else + set_temp("[servers.len] SERVERS PROBED & BUFFERED", "good") + . = TRUE - if(!servers.len) - temp = "- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -" - else - temp = "- [servers.len] SERVERS PROBED & BUFFERED -" - - screen = 0 - - if(href_list["delete"]) - - if(!src.allowed(usr) && !emagged) + if("delete") + if(!allowed(usr) && !emagged) to_chat(usr, "ACCESS DENIED.") return if(SelectedServer) - - var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])] - - temp = "- DELETED ENTRY: [D.name] -" - + var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(params["id"])] + set_temp("DELETED ENTRY: [D.name]", "bad") SelectedServer.log_entries.Remove(D) qdel(D) - else - temp = "- FAILED: NO SELECTED MACHINE -" - - if(href_list["network"]) + set_temp("FAILED: NO SELECTED MACHINE", "bad") + . = TRUE + if("network") var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text if(newnet && ((usr in range(1, src) || issilicon(usr)))) if(length(newnet) > 15) - temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" + set_temp("FAILED: NETWORK TAG STRING TOO LENGTHY", "bad") + return TRUE + network = newnet + servers = list() + set_temp("NEW NETWORK TAG SET IN ADDRESS \[[network]\]", "good") - else - - network = newnet - screen = 0 - servers = list() - temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" - - updateUsrDialog() - return + . = TRUE + + if("cleartemp") + temp = null + . = TRUE /obj/machinery/computer/telecomms/server/emag_act(var/remaining_charges, var/mob/user) if(!emagged) @@ -197,3 +148,6 @@ to_chat(user, "You you disable the security protocols") src.updateUsrDialog() return 1 + +/obj/machinery/computer/telecomms/server/proc/set_temp(var/text, var/color = "average") + temp = list("color" = color, "text" = text) \ No newline at end of file diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index d1449882af..7a14fa2023 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -11,8 +11,7 @@ #define TELECOMM_Z 3 /obj/machinery/telecomms - var/temp = "" // output message - + var/list/temp = null // output message /obj/machinery/telecomms/attackby(obj/item/P as obj, mob/user as mob) @@ -40,74 +39,72 @@ /obj/machinery/telecomms/attack_ai(var/mob/user as mob) attack_hand(user) -/obj/machinery/telecomms/attack_hand(var/mob/user as mob) +/obj/machinery/telecomms/tgui_data(mob/user) + var/list/data = list() + + data["temp"] = temp + data["on"] = on - // You need a multitool to use this, or be silicon - if(!issilicon(user)) - // istype returns false if the value is null - if(!istype(user.get_active_hand(), /obj/item/device/multitool)) - return + data["id"] = null + data["network"] = null + data["autolinkers"] = FALSE + data["shadowlink"] = FALSE + data["options"] = list() + data["linked"] = list() + data["filter"] = list() + data["multitool"] = FALSE + data["multitool_buffer"] = null - if(stat & (BROKEN|NOPOWER)) - return + if(on || interact_offline) + data["id"] = id + data["network"] = network + data["autolinkers"] = !!LAZYLEN(autolinkers) + data["shadowlink"] = !!hide - var/obj/item/device/multitool/P = get_multitool(user) + data["options"] = Options_Menu() - user.set_machine(src) - var/dat - dat = "[src.name]

[src.name] Access

" - dat += "
[temp]
" - dat += "
Power Status: [src.toggled ? "On" : "Off"]" - if(on && toggled) - if(id != "" && id) - dat += "
Identification String: [id]" - else - dat += "
Identification String: NULL" - dat += "
Network: [network]" - dat += "
Prefabrication: [autolinkers.len ? "TRUE" : "FALSE"]" - if(hide) dat += "
Shadow Link: ACTIVE" - - //Show additional options for certain machines. - dat += Options_Menu() - - dat += "
Linked Network Entities:
    " + var/obj/item/device/multitool/P = get_multitool(user) + data["multitool"] = !!P + data["multitool_buffer"] = null + if(P && P.buffer) + P.update_icon() + data["multitool_buffer"] = list("name" = "[P.buffer]", "id" = "[P.buffer.id]") var/i = 0 + data["linked"] = list() for(var/obj/machinery/telecomms/T in links) i++ - if(T.hide && !src.hide) - continue - dat += "
  1. \ref[T] [T.name] ([T.id]) \[X\]
  2. " - dat += "
" - - dat += "
Filtering Frequencies: " - - i = 0 - if(length(freq_listening)) + data["linked"].Add(list(list( + "ref" = "\ref[T]", + "name" = "[T]", + "id" = T.id, + "index" = i, + ))) + + data["filter"] = list() + if(LAZYLEN(freq_listening)) for(var/x in freq_listening) - i++ - if(i < length(freq_listening)) - dat += "[format_frequency(x)] GHz\[X\]; " - else - dat += "[format_frequency(x)] GHz\[X\]" - else - dat += "NONE" + data["filter"].Add(list(list( + "name" = "[format_frequency(x)]", + "freq" = x, + ))) - dat += "
\[Add Filter\]" - dat += "
" + return data - if(P) - if(P.buffer) - dat += "

MULTITOOL BUFFER: [P.buffer] ([P.buffer.id]) \[Link\] \[Flush\]" - else - dat += "

MULTITOOL BUFFER:
\[Add Machine\]" - P.update_icon() +/obj/machinery/telecomms/tgui_status(mob/user) + if(!issilicon(user)) + if(!istype(user.get_active_hand(), /obj/item/device/multitool)) + return STATUS_CLOSE + . = ..() - dat += "
" - temp = "" - user << browse(dat, "window=tcommachine;size=520x500;can_resize=0") - onclose(user, "dormitory") +/obj/machinery/telecomms/attack_hand(var/mob/user as mob) + tgui_interact(user) +/obj/machinery/telecomms/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TelecommsMultitoolMenu", name) + ui.open() // Off-Site Relays // @@ -148,7 +145,7 @@ // Example of how to use below. /obj/machinery/telecomms/proc/Options_Menu() - return "" + return list() /* // Add an option to the processor to switch processing mode. (COMPRESS -> UNCOMPRESS or UNCOMPRESS -> COMPRESS) @@ -158,213 +155,230 @@ */ // The topic for Additional Options. Use this for checking href links for your specific option. // Example of how to use below. -/obj/machinery/telecomms/proc/Options_Topic(href, href_list) +/obj/machinery/telecomms/proc/Options_Act(action, params) return /* -/obj/machinery/telecomms/processor/Options_Topic(href, href_list) +/obj/machinery/telecomms/processor/Options_Act(action, params) if(href_list["process"]) - temp = "-% Processing mode changed. %-" + set_temp("-% Processing mode changed. %-", "average") src.process_mode = !src.process_mode */ // RELAY /obj/machinery/telecomms/relay/Options_Menu() - var/dat = "" - if(src.z == TELECOMM_Z) - dat += "
Signal Locked to Station: [listening_level == STATION_Z ? "TRUE" : "FALSE"]" - dat += "
Broadcasting: [broadcasting ? "YES" : "NO"]" - dat += "
Receiving: [receiving ? "YES" : "NO"]" - return dat + var/list/data = ..() + data["use_listening_level"] = TRUE + data["use_broadcasting"] = TRUE + data["use_receiving"] = TRUE + data["listening_level"] = (listening_level == STATION_Z) + data["broadcasting"] = broadcasting + data["receiving"] = receiving + return data -/obj/machinery/telecomms/relay/Options_Topic(href, href_list) +/obj/machinery/telecomms/relay/Options_Act(action, params) + if(..()) + return TRUE - if(href_list["receive"]) - receiving = !receiving - temp = "-% Receiving mode changed. %-" - if(href_list["broadcast"]) - broadcasting = !broadcasting - temp = "-% Broadcasting mode changed. %-" - if(href_list["change_listening"]) - //Lock to the station OR lock to the current position! - //You need at least two receivers and two broadcasters for this to work, this includes the machine. - var/result = toggle_level() - if(result) - temp = "-% [src]'s signal has been successfully changed." - else - temp = "-% [src] could not lock it's signal onto the station. Two broadcasters or receivers required." + switch(action) + if("receive") + . = TRUE + receiving = !receiving + set_temp("-% Receiving mode changed. %-", "average") + if("broadcast") + . = TRUE + broadcasting = !broadcasting + set_temp("-% Broadcasting mode changed. %-", "average") + if("change_listening") + . = TRUE + //Lock to the station OR lock to the current position! + //You need at least two receivers and two broadcasters for this to work, this includes the machine. + var/result = toggle_level() + if(result) + set_temp("-% [src]'s signal has been successfully changed.", "average") + else + set_temp("-% [src] could not lock it's signal onto the station. Two broadcasters or receivers required.", "average") // BUS /obj/machinery/telecomms/bus/Options_Menu() - var/dat = "
Change Signal Frequency: [change_frequency ? "YES ([change_frequency])" : "NO"]" - return dat + var/list/data = ..() + data["use_change_freq"] = TRUE + data["change_freq"] = change_frequency + return data -/obj/machinery/telecomms/bus/Options_Topic(href, href_list) - - if(href_list["change_freq"]) - - var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null|num - if(canAccess(usr)) - if(newfreq) - if(findtext(num2text(newfreq), ".")) - newfreq *= 10 // shift the decimal one place - if(newfreq < 10000) - change_frequency = newfreq - temp = "-% New frequency to change to assigned: \"[newfreq] GHz\" %-" - else - change_frequency = 0 - temp = "-% Frequency changing deactivated %-" +/obj/machinery/telecomms/bus/Options_Act(action, params) + if(..()) + return TRUE + + switch(action) + if("change_freq") + . = TRUE + var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null|num + if(canAccess(usr)) + if(newfreq) + if(findtext(num2text(newfreq), ".")) + newfreq *= 10 // shift the decimal one place + if(newfreq < 10000) + change_frequency = newfreq + set_temp("-% New frequency to change to assigned: \"[newfreq] GHz\" %-", "average") + else + change_frequency = 0 + set_temp("-% Frequency changing deactivated %-", "average") // BROADCASTER /obj/machinery/telecomms/broadcaster/Options_Menu() - // Note the machine 'displays' 1 higher than overmap_range to save users from the abstraction that range '0' is valid and everything on the same turf. - var/dat = "
Broadcast Range (affects power usage)
- [overmap_range+1] gigameter\s +" - return dat + var/list/data = ..() + data["use_broadcast_range"] = TRUE + data["range"] = overmap_range + data["minRange"] = overmap_range_min + data["maxRange"] = overmap_range_max + return data -/obj/machinery/telecomms/broadcaster/Options_Topic(href, href_list) - if(href_list["range_down"]) - if(overmap_range > overmap_range_min) - overmap_range-- - update_idle_power_usage(initial(idle_power_usage)**(overmap_range+1)) - if(href_list["range_up"]) - if(overmap_range < overmap_range_max) - overmap_range++ +/obj/machinery/telecomms/broadcaster + interact_offline = TRUE // because you can accidentally nuke power grids with these, need to be able to fix mistake + +/obj/machinery/telecomms/broadcaster/Options_Act(action, params) + if(..()) + return TRUE + + switch(action) + if("range") + var/new_range = params["range"] + overmap_range = clamp(new_range, overmap_range_min, overmap_range_max) update_idle_power_usage(initial(idle_power_usage)**(overmap_range+1)) // RECEIVER /obj/machinery/telecomms/receiver/Options_Menu() - // Note the machine 'displays' 1 higher than overmap_range to save users from the abstraction that range '0' is valid and everything on the same turf. - var/dat = "
Receive Range (affects power usage)
- [overmap_range+1] gigameter\s +" - return dat + var/list/data = ..() + data["use_receive_range"] = TRUE + data["range"] = overmap_range + data["minRange"] = overmap_range_min + data["maxRange"] = overmap_range_max + return data -/obj/machinery/telecomms/receiver/Options_Topic(href, href_list) - if(href_list["range_down"]) - if(overmap_range > overmap_range_min) - overmap_range-- - update_idle_power_usage(initial(idle_power_usage)**(overmap_range+1)) - if(href_list["range_up"]) - if(overmap_range < overmap_range_max) - overmap_range++ +/obj/machinery/telecomms/receiver + interact_offline = TRUE // because you can accidentally nuke power grids with these, need to be able to fix mistake + +/obj/machinery/telecomms/receiver/Options_Act(action, params) + if(..()) + return TRUE + + switch(action) + if("range") + var/new_range = params["range"] + overmap_range = clamp(new_range, overmap_range_min, overmap_range_max) update_idle_power_usage(initial(idle_power_usage)**(overmap_range+1)) -/obj/machinery/telecomms/Topic(href, href_list) - - if(!issilicon(usr)) - if(!istype(usr.get_active_hand(), /obj/item/device/multitool)) - return - - if(stat & (BROKEN|NOPOWER)) - return +/obj/machinery/telecomms/tgui_act(action, params) + if(..()) + return TRUE var/obj/item/device/multitool/P = get_multitool(usr) - if(href_list["input"]) - switch(href_list["input"]) + switch(action) + if("toggle") + src.toggled = !src.toggled + set_temp("-% [src] has been [src.toggled ? "activated" : "deactivated"].", "average") + update_power() + . = TRUE - if("toggle") + if("id") + var/newid = copytext(reject_bad_text(input(usr, "Specify the new ID for this machine", src, id) as null|text),1,MAX_MESSAGE_LEN) + if(newid && canAccess(usr)) + id = newid + set_temp("-% New ID assigned: \"[id]\" %-", "average") + . = TRUE - src.toggled = !src.toggled - temp = "-% [src] has been [src.toggled ? "activated" : "deactivated"]." - update_power() + if("network") + var/newnet = input(usr, "Specify the new network for this machine. This will break all current links.", src, network) as null|text + if(newnet && canAccess(usr)) - /* - if("hide") - src.hide = !hide - temp = "-% Shadow Link has been [src.hide ? "activated" : "deactivated"]." - */ + if(length(newnet) > 15) + set_temp("-% Too many characters in new network tag %-", "average") - if("id") - var/newid = copytext(reject_bad_text(input(usr, "Specify the new ID for this machine", src, id) as null|text),1,MAX_MESSAGE_LEN) - if(newid && canAccess(usr)) - id = newid - temp = "-% New ID assigned: \"[id]\" %-" + else + for(var/obj/machinery/telecomms/T in links) + T.links.Remove(src) - if("network") - var/newnet = input(usr, "Specify the new network for this machine. This will break all current links.", src, network) as null|text - if(newnet && canAccess(usr)) - - if(length(newnet) > 15) - temp = "-% Too many characters in new network tag %-" - - else - for(var/obj/machinery/telecomms/T in links) - T.links.Remove(src) - - network = newnet - links = list() - temp = "-% New network tag assigned: \"[network]\" %-" + network = newnet + links = list() + set_temp("-% New network tag assigned: \"[network]\" %-", "average") + . = TRUE - if("freq") - var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null|num - if(newfreq && canAccess(usr)) - if(findtext(num2text(newfreq), ".")) - newfreq *= 10 // shift the decimal one place - if(!(newfreq in freq_listening) && newfreq < 10000) - freq_listening.Add(newfreq) - temp = "-% New frequency filter assigned: \"[newfreq] GHz\" %-" + if("freq") + var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null|num + if(newfreq && canAccess(usr)) + if(findtext(num2text(newfreq), ".")) + newfreq *= 10 // shift the decimal one place + if(!(newfreq in freq_listening) && newfreq < 10000) + freq_listening.Add(newfreq) + set_temp("-% New frequency filter assigned: \"[newfreq] GHz\" %-", "average") + . = TRUE - if(href_list["delete"]) + if("delete") + var/x = text2num(params["delete"]) + set_temp("-% Removed frequency filter [x] %-", "average") + freq_listening.Remove(x) + . = TRUE - // changed the layout about to workaround a pesky runtime -- Doohl + if("unlink") + if(text2num(params["unlink"]) <= length(links)) + var/obj/machinery/telecomms/T = links[text2num(params["unlink"])] + set_temp("-% Removed \ref[T] [T.name] from linked entities. %-", "average") - var/x = text2num(href_list["delete"]) - temp = "-% Removed frequency filter [x] %-" - freq_listening.Remove(x) + // Remove link entries from both T and src. - if(href_list["unlink"]) + if(src in T.links) + T.links.Remove(src) + links.Remove(T) + . = TRUE - if(text2num(href_list["unlink"]) <= length(links)) - var/obj/machinery/telecomms/T = links[text2num(href_list["unlink"])] - temp = "-% Removed \ref[T] [T.name] from linked entities. %-" + if("link") + if(P) + if(P.buffer && P.buffer != src) + if(!(src in P.buffer.links)) + P.buffer.links.Add(src) - // Remove link entries from both T and src. + if(!(P.buffer in src.links)) + src.links.Add(P.buffer) - if(src in T.links) - T.links.Remove(src) - links.Remove(T) + set_temp("-% Successfully linked with \ref[P.buffer] [P.buffer.name] %-", "average") - if(href_list["link"]) + else + set_temp("-% Unable to acquire buffer %-", "average") + . = TRUE - if(P) - if(P.buffer && P.buffer != src) - if(!(src in P.buffer.links)) - P.buffer.links.Add(src) + if("buffer") + P.buffer = src + set_temp("-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-", "average") + . = TRUE - if(!(P.buffer in src.links)) - src.links.Add(P.buffer) + if("flush") + set_temp("-% Buffer successfully flushed. %-", "average") + P.buffer = null + . = TRUE - temp = "-% Successfully linked with \ref[P.buffer] [P.buffer.name] %-" + if("cleartemp") + temp = null + . = TRUE - else - temp = "-% Unable to acquire buffer %-" + if(Options_Act(action, params)) + . = TRUE - if(href_list["buffer"]) - - P.buffer = src - temp = "-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-" - - - if(href_list["flush"]) - - temp = "-% Buffer successfully flushed. %-" - P.buffer = null - - src.Options_Topic(href, href_list) - - usr.set_machine(src) - src.add_fingerprint(usr) - - updateUsrDialog() + add_fingerprint(usr) /obj/machinery/telecomms/proc/canAccess(var/mob/user) if(issilicon(user) || in_range(user, src)) return 1 return 0 +/obj/machinery/telecomms/proc/set_temp(var/text, var/color = "average") + temp = list("color" = color, "text" = text) + #undef TELECOMM_Z #undef STATION_Z diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 3799d06b07..6f2e626a00 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -593,6 +593,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() log.parameters["message"] = multilingual_to_message(signal.data["message"]) log.parameters["name"] = signal.data["name"] log.parameters["realname"] = signal.data["realname"] + log.parameters["timecode"] = worldtime2stationtime(world.time) var/race = "unknown" if(ishuman(M)) @@ -672,6 +673,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() log.name = "[input] ([md5(identifier)])" log.input_type = input log.parameters["message"] = content + log.parameters["timecode"] = stationtime2text() log_entries.Add(log) update_logs() diff --git a/code/game/machinery/telecomms/telemonitor.dm b/code/game/machinery/telecomms/telemonitor.dm index 51a6ebf991..7107e0ff5d 100644 --- a/code/game/machinery/telecomms/telemonitor.dm +++ b/code/game/machinery/telecomms/telemonitor.dm @@ -6,7 +6,6 @@ and displays a heirarchy of linked machines. */ - /obj/machinery/computer/telecomms/monitor name = "Telecommunications Monitor" desc = "Used to traverse a telecommunication network. Helpful for debugging connection issues." @@ -19,111 +18,103 @@ var/network = "NULL" // the network to probe - var/temp = "" // temporary feedback messages + var/list/temp = null // temporary feedback messages - attack_hand(mob/user as mob) - if(stat & (BROKEN|NOPOWER)) - return - user.set_machine(src) - var/dat = "Telecommunications Monitor
Telecommunications Monitor
" +/obj/machinery/computer/telecomms/monitor/tgui_data(mob/user) + var/list/data = list() - switch(screen) + data["network"] = network + data["temp"] = temp + data["machinelist"] = list() + for(var/obj/machinery/telecomms/T in machinelist) + data["machinelist"].Add(list(list( + "id" = T.id, + "name" = T.name, + ))) - // --- Main Menu --- + data["selectedMachine"] = null + if(SelectedMachine) + data["selectedMachine"] = list( + "id" = SelectedMachine.id, + "name" = SelectedMachine.name, + "links" = list(), + ) - if(0) - dat += "
[temp]

" - dat += "
Current Network: [network]
" - if(machinelist.len) - dat += "
Detected Network Entities:" - dat += "
\[Flush Buffer\]" - else - dat += "\[Probe Network\]" + for(var/obj/machinery/telecomms/T in SelectedMachine.links) + if(!T.hide) + data["selectedMachine"]["links"].Add(list(list( + "id" = T.id, + "name" = T.name + ))) + return data - // --- Viewing Machine --- - - if(1) - dat += "
[temp]
" - dat += "
\[Main Menu\]
" - dat += "
Current Network: [network]
" - dat += "Selected Network Entity: [SelectedMachine.name] ([SelectedMachine.id])
" - dat += "Linked Entities:
    " - for(var/obj/machinery/telecomms/T in SelectedMachine.links) - if(!T.hide) - dat += "
  1. \ref[T.id] [T.name] ([T.id])
  2. " - dat += "
" - - - - user << browse(dat, "window=comm_monitor;size=575x400") - onclose(user, "server_control") - - temp = "" +/obj/machinery/computer/telecomms/monitor/attack_hand(mob/user) + if(stat & (BROKEN|NOPOWER)) return + tgui_interact(user) +/obj/machinery/computer/telecomms/monitor/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TelecommsMachineBrowser", name) + ui.open() - Topic(href, href_list) - if(..()) - return +/obj/machinery/computer/telecomms/monitor/tgui_act(action, params) + if(..()) + return TRUE + add_fingerprint(usr) - add_fingerprint(usr) - usr.set_machine(src) - - if(href_list["viewmachine"]) - screen = 1 + switch(action) + if("view") for(var/obj/machinery/telecomms/T in machinelist) - if(T.id == href_list["viewmachine"]) + if(T.id == params["id"]) SelectedMachine = T break + . = TRUE - if(href_list["operation"]) - switch(href_list["operation"]) + if("mainmenu") + SelectedMachine = null + . = TRUE - if("release") - machinelist = list() - screen = 0 + if("release") + machinelist = list() + SelectedMachine = null + . = TRUE - if("mainmenu") - screen = 0 + if("scan") + if(machinelist.len > 0) + set_temp("FAILED: CANNOT PROBE WHEN BUFFER FULL", "bad") + return TRUE - if("probe") - if(machinelist.len > 0) - temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" + for(var/obj/machinery/telecomms/T in range(25, src)) + if(T.network == network) + machinelist.Add(T) - else - for(var/obj/machinery/telecomms/T in range(25, src)) - if(T.network == network) - machinelist.Add(T) - - if(!machinelist.len) - temp = "- FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\] -" - else - temp = "- [machinelist.len] ENTITIES LOCATED & BUFFERED -" - - screen = 0 - - - if(href_list["network"]) + if(!machinelist.len) + set_temp("FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\]", "bad") + else + set_temp("[machinelist.len] ENTITIES LOCATED & BUFFERED", "good") + . = TRUE + if("network") var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text if(newnet && ((usr in range(1, src) || issilicon(usr)))) if(length(newnet) > 15) - temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" + set_temp("FAILED: NETWORK TAG STRING TOO LENGTHY", "bad") + return TRUE + network = newnet + machinelist = list() + set_temp("NEW NETWORK TAG SET IN ADDRESS \[[network]\]", "good") + + . = TRUE - else - network = newnet - screen = 0 - machinelist = list() - temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" + if("cleartemp") + temp = null + . = TRUE - updateUsrDialog() - return /obj/machinery/computer/telecomms/monitor/emag_act(var/remaining_charges, var/mob/user) if(!emagged) @@ -132,3 +123,6 @@ to_chat(user, "You you disable the security protocols") src.updateUsrDialog() return 1 + +/obj/machinery/computer/telecomms/monitor/proc/set_temp(var/text, var/color = "average") + temp = list("color" = color, "text" = text) \ No newline at end of file diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 5ff60979d0..dcdd8d88fe 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -26,6 +26,7 @@ var/vend_delay = 10 //How long does it take to vend? var/categories = CAT_NORMAL // Bitmask of cats we're currently showing var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now + var/tmp/actively_vending = null // Used to allow TGUI to display normal items in-progress being vended var/status_message = "" // Status screen messages like "insufficient funds", displayed in NanoUI var/status_error = 0 // Set to 1 if status_message is an error var/vending_sound = "machines/vending/vending_drop.ogg" @@ -173,7 +174,7 @@ vend(currently_vending, usr) return else if(handled) - SSnanoui.update_uis(src) + SStgui.update_uis(src) return // don't smack that machine with your 2 thalers if(I || istype(W, /obj/item/weapon/spacecash)) @@ -184,11 +185,12 @@ to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") playsound(src, W.usesound, 50, 1) if(panel_open) + wires.Interact(user) add_overlay("[initial(icon_state)]-panel") else cut_overlay("[initial(icon_state)]-panel") - SSnanoui.update_uis(src) // Speaker switch is on the main UI, not wires UI + SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI return else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter()) if(panel_open) @@ -200,7 +202,7 @@ coin = W categories |= CAT_COIN to_chat(user, "You insert \the [W] into \the [src].") - SSnanoui.update_uis(src) + SStgui.update_uis(src) return else if(W.is_wrench()) playsound(src, W.usesound, 100, 1) @@ -348,6 +350,9 @@ T.time = stationtime2text() vendor_account.transaction_log.Add(T) +/obj/machinery/vending/attack_ghost(mob/user) + return attack_hand(user) + /obj/machinery/vending/attack_ai(mob/user as mob) return attack_hand(user) @@ -360,24 +365,23 @@ return wires.Interact(user) - ui_interact(user) + tgui_interact(user) -/** - * Display the NanoUI window for the vending machine. - * - * See NanoUI documentation for details. - */ -/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Vending", name) + ui.open() +/obj/machinery/vending/tgui_data(mob/user) var/list/data = list() if(currently_vending) data["mode"] = 1 data["product"] = currently_vending.item_name data["price"] = currently_vending.price - data["message_err"] = 0 data["message"] = status_message data["message_err"] = status_error + data["products"] = null else data["mode"] = 0 var/list/listed_products = list() @@ -399,6 +403,13 @@ if(coin) data["coin"] = coin.name + else + data["coin"] = FALSE + + if(actively_vending) + data["actively_vending"] = actively_vending + else + data["actively_vending"] = null if(panel_open) data["panel"] = 1 @@ -406,19 +417,20 @@ else data["panel"] = 0 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "vending_machine.tmpl", name, 440, 600) - ui.set_initial_data(data) - ui.open() + return data -/obj/machinery/vending/Topic(href, href_list) +/obj/machinery/vending/tgui_act(action, params) if(stat & (BROKEN|NOPOWER)) return if(usr.stat || usr.restrained()) return + if(..()) + return TRUE + + if(action == "remove_coin") + if(issilicon(usr)) + return FALSE - if(href_list["remove_coin"] && !istype(usr,/mob/living/silicon)) if(!coin) to_chat(usr, "There is no coin in this machine.") return @@ -426,19 +438,27 @@ coin.forceMove(src.loc) if(!usr.get_active_hand()) usr.put_in_hands(coin) - to_chat(usr, "You remove \the [coin] from \the [src]") + + to_chat(usr, "You remove \the [coin] from \the [src].") coin = null categories &= ~CAT_COIN + return TRUE - if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) - if((href_list["vend"]) && (vend_ready) && (!currently_vending)) - if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + if(!usr.contents.Find(src) && (!in_range(src, usr) && isturf(loc))) + return FALSE + + . = TRUE + switch(action) + if("vend") + if(!vend_ready || currently_vending) + return + if(!allowed(usr) && !emagged && scan_id) to_chat(usr, "Access denied.") //Unless emagged of course flick("[icon_state]-deny",src) playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) return - var/key = text2num(href_list["vend"]) + var/key = text2num(params["vend"]) var/datum/stored_item/vending_product/R = product_records[key] // This should not happen unless the request from NanoUI was bad @@ -447,7 +467,7 @@ if(R.price <= 0) vend(R, usr) - else if(istype(usr,/mob/living/silicon)) //If the item is not free, provide feedback if a synth is trying to buy something. + else if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something. to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.") return else @@ -459,15 +479,14 @@ status_message = "Please swipe a card or insert cash to pay for the item." status_error = 0 - else if(href_list["cancelpurchase"]) + if("cancelpurchase") currently_vending = null - else if((href_list["togglevoice"]) && (panel_open)) + if("togglevoice") + if(!panel_open) + return FALSE shut_up = !shut_up - add_fingerprint(usr) - SSnanoui.update_uis(src) - /obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user) if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH to_chat(usr, "Access denied.") //Unless emagged of course @@ -475,9 +494,10 @@ playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) return vend_ready = 0 //One thing at a time!! + actively_vending = R.item_name status_message = "Vending..." status_error = 0 - SSnanoui.update_uis(src) + SStgui.update_uis(src) if(R.category & CAT_COIN) if(!coin) @@ -516,8 +536,9 @@ status_message = "" status_error = 0 vend_ready = 1 + actively_vending = null currently_vending = null - SSnanoui.update_uis(src) + SStgui.update_uis(src) return 1 @@ -589,7 +610,7 @@ if(has_logs) do_logging(R, user) - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/vending/process() if(stat & (BROKEN|NOPOWER)) diff --git a/code/game/objects/effects/map_effects/portal.dm b/code/game/objects/effects/map_effects/portal.dm index 93cbd0c53f..2331cac8e8 100644 --- a/code/game/objects/effects/map_effects/portal.dm +++ b/code/game/objects/effects/map_effects/portal.dm @@ -1,344 +1,344 @@ -GLOBAL_LIST_EMPTY(all_portal_masters) - -/* - -Portal map effects allow a mapper to join two distant places together, while looking somewhat seamlessly connected. -This can allow for very strange PoIs that twist and turn in what appear to be physically impossible ways. - -Portals do have some specific requirements when mapping them in; - - There must by one, and only one `/obj/effect/map_effect/portal/master` for each side of a portal. - - Both sides need to have matching `portal_id`s in order to link to each other. - - Each side must face opposite directions, e.g. if side A faces SOUTH, side B must face NORTH. - - Each side must have the same orientation, e.g. horizontal on both sides, or vertical on both sides. - - Portals can be made to be longer than 1x1 with `/obj/effect/map_effect/portal/line`s, - but both sides must have the same length. - - If portal lines are added, they must form a straight line and be next to a portal master or another portal line. - - If portal lines are used, both portal masters should be in the same relative position among the lines. - E.g. both being on the left most side on a horizontal row. - -Portals also have some limitations to be aware of when mapping. Some of these are not an issue if you're trying to make an 'obvious' portal; - - The objects seen through portals are purely visual, which has many implications, - such as simple_mob AIs being blind to mobs on the other side of portals. - - Objects on the other side of a portal can be interacted with if the interaction has no range limitation, - or the distance between the two portal sides happens to be less than the interaction max range. Examine will probably work, - while picking up an item that appears to be next to you will fail. - - Sounds currently are not carried across portals. - - Mismatched lighting between each portal end can make the portal look obvious. - - Portals look weird when observing as a ghost, or otherwise when able to see through walls. Meson vision will also spoil the illusion. - - Walls that change icons based on neightboring walls can give away that a portal is nearby if both sides don't have a similar transition. - - Projectiles that pass through portals will generally work as intended, however aiming and firing upon someone on the other side of a portal - will likely be weird due to the click targeting the real position of the thing clicked instead of the apparent position. - Thrown objects suffer a similar fate. - - The tiles that are visually shown across a portal are determined based on visibility at the time of portal initialization, - and currently don't update, meaning that opacity changes are not reflected, e.g. a wall is deconstructed, or an airlock is opened. - - There is currently a small but somewhat noticable pause in mob movement when moving across a portal, - as a result of the mob's glide animation being inturrupted by a teleport. - - Gas is not transferred through portals, and ZAS is oblivious to them. - -A lot of those limitations can potentially be solved with some more work. Otherwise, portals work best in static environments like Points of Interest, -when portals are shortly lived, or when portals are made to be obvious with special effects. -*/ - -/obj/effect/map_effect/portal - name = "portal subtype" - invisibility = 0 - opacity = TRUE - plane = TURF_PLANE - layer = ABOVE_TURF_LAYER - appearance_flags = PIXEL_SCALE|KEEP_TOGETHER // Removed TILE_BOUND so things not visible on the other side stay hidden from the viewer. - - var/obj/effect/map_effect/portal/counterpart = null // The portal line or master that this is connected to, on the 'other side'. - - // Information used to apply `pixel_[x|y]` offsets so that the visuals line up. - // Set automatically by `calculate_dimensions()`. - var/total_height = 0 // Measured in tiles. - var/total_width = 0 - - var/portal_distance_x = 0 // How far the portal is from the left edge, in tiles. - var/portal_distance_y = 0 // How far the portal is from the top edge. - -/obj/effect/map_effect/portal/Destroy() - vis_contents = null - if(counterpart) - counterpart.counterpart = null // Disconnect our counterpart from us - counterpart = null // Now disconnect us from them. - return ..() - -// Called when something touches the portal, and usually teleports them to the other side. -/obj/effect/map_effect/portal/Crossed(atom/movable/AM) - if(AM.is_incorporeal()) - return - ..() - if(!AM) - return - if(!counterpart) - return - - go_through_portal(AM) - - -/obj/effect/map_effect/portal/proc/go_through_portal(atom/movable/AM) - // TODO: Find a way to fake the glide or something. - if(isliving(AM)) - var/mob/living/L = AM - if(L.pulling) - var/atom/movable/pulled = L.pulling - L.stop_pulling() - // For some reason, trying to put the pulled object behind the person makes the drag stop and it doesn't even move to the other side. - // pulled.forceMove(get_turf(counterpart)) - pulled.forceMove(counterpart.get_focused_turf()) - L.forceMove(counterpart.get_focused_turf()) - L.start_pulling(pulled) - else - L.forceMove(counterpart.get_focused_turf()) - else - AM.forceMove(counterpart.get_focused_turf()) - -// 'Focused turf' is the turf directly in front of a portal, -// and it is used both as the destination when crossing, as well as the PoV for visuals. -/obj/effect/map_effect/portal/proc/get_focused_turf() - return get_step(get_turf(src), dir) - -// Determines the size of the block of turfs inside `vis_contents`, and where the portal is in relation to that. -/obj/effect/map_effect/portal/proc/calculate_dimensions() - var/highest_x = 0 - var/lowest_x = 0 - - var/highest_y = 0 - var/lowest_y = 0 - - // First pass is for finding the top right corner. - for(var/thing in vis_contents) - var/turf/T = thing - if(T.x > highest_x) - highest_x = T.x - if(T.y > highest_y) - highest_y = T.y - - lowest_x = highest_x - lowest_y = highest_y - - // Second one is for the bottom left corner. - for(var/thing in vis_contents) - var/turf/T = thing - if(T.x < lowest_x) - lowest_x = T.x - if(T.y < lowest_y) - lowest_y = T.y - - // Now calculate the dimensions. - total_width = (highest_x - lowest_x) + 1 - total_height = (highest_y - lowest_y) + 1 - - // Find how far the portal is from the edges. - var/turf/focused_T = counterpart.get_focused_turf() - portal_distance_x = lowest_x - focused_T.x - portal_distance_y = lowest_y - focused_T.y - - -// Portal masters manage everything else involving portals. -// This is the base type. Use `/side_a` or `/side_b` with matching IDs for actual portals. -/obj/effect/map_effect/portal/master - name = "portal master" - show_messages = TRUE // So portals can hear and see, and relay to the other side. - var/portal_id = "test" // For a portal to be made, both the A and B sides need to share the same ID value. - var/list/portal_lines = list() - -/obj/effect/map_effect/portal/master/Initialize() - GLOB.all_portal_masters += src - find_lines() - ..() - return INITIALIZE_HINT_LATELOAD - -/obj/effect/map_effect/portal/master/LateInitialize() - find_counterparts() - make_visuals() - apply_offset() - -/obj/effect/map_effect/portal/master/Destroy() - GLOB.all_portal_masters -= src - for(var/thing in portal_lines) - qdel(thing) - return ..() - -/obj/effect/map_effect/portal/master/proc/find_lines() - var/list/dirs_to_search = list( turn(dir, 90), turn(dir, -90) ) - - for(var/dir_to_search in dirs_to_search) - var/turf/current_T = get_turf(src) - while(current_T) - current_T = get_step(current_T, dir_to_search) - var/obj/effect/map_effect/portal/line/line = locate() in current_T - if(line) - portal_lines += line - line.my_master = src - else - break - -// Connects both sides of a portal together. -/obj/effect/map_effect/portal/master/proc/find_counterparts() - for(var/thing in GLOB.all_portal_masters) - var/obj/effect/map_effect/portal/master/M = thing - if(M == src) - continue - if(M.counterpart) - continue - - if(M.portal_id == src.portal_id) - counterpart = M - M.counterpart = src - if(portal_lines.len) - for(var/i = 1 to portal_lines.len) - var/obj/effect/map_effect/portal/line/our_line = portal_lines[i] - var/obj/effect/map_effect/portal/line/their_line = M.portal_lines[i] - our_line.counterpart = their_line - their_line.counterpart = our_line - break - - if(!counterpart) - crash_with("Portal master [type] ([x],[y],[z]) could not find another portal master with a matching portal_id ([portal_id]).") - -/obj/effect/map_effect/portal/master/proc/make_visuals() - var/list/observed_turfs = list() - for(var/thing in portal_lines + src) - var/obj/effect/map_effect/portal/P = thing - P.name = null - P.icon_state = null - - if(!P.counterpart) - return - - var/turf/T = P.counterpart.get_focused_turf() - P.vis_contents += T - - var/list/things = dview(world.view, T) - for(var/turf/turf in things) - if(get_dir(turf, T) & P.dir) - if(turf in observed_turfs) // Avoid showing the same turf twice or more for improved performance. - continue - - P.vis_contents += turf - observed_turfs += turf - - P.calculate_dimensions() - -// Shifts the portal's pixels in order to line up properly, as BYOND offsets the sprite when it holds multiple turfs inside `vis_contents`. -// This undos the shift that BYOND did. -/obj/effect/map_effect/portal/master/proc/apply_offset() - for(var/thing in portal_lines + src) - var/obj/effect/map_effect/portal/P = thing - - P.pixel_x = WORLD_ICON_SIZE * P.portal_distance_x - P.pixel_y = WORLD_ICON_SIZE * P.portal_distance_y - -// Allows portals to transfer emotes. -// Only portal masters do this to avoid flooding the other side with duplicate messages. -/obj/effect/map_effect/portal/master/see_emote(mob/M, text) - if(!counterpart) - return - var/turf/T = counterpart.get_focused_turf() - var/list/in_range = get_mobs_and_objs_in_view_fast(T, world.view, 0) - var/list/mobs_to_relay = in_range["mobs"] - - for(var/thing in mobs_to_relay) - var/mob/mob = thing - var/rendered = "[text]" - mob.show_message(rendered) - - ..() - -// Allows portals to transfer visible messages. -/obj/effect/map_effect/portal/master/show_message(msg, type, alt, alt_type) - if(!counterpart) - return - var/rendered = "[msg]" - var/turf/T = counterpart.get_focused_turf() - var/list/in_range = get_mobs_and_objs_in_view_fast(T, world.view, 0) - var/list/mobs_to_relay = in_range["mobs"] - - for(var/thing in mobs_to_relay) - var/mob/mob = thing - mob.show_message(rendered) - - ..() - -// Allows portals to transfer speech. -/obj/effect/map_effect/portal/master/hear_talk(mob/M, list/message_pieces, verb) - if(!counterpart) - return - var/turf/T = counterpart.get_focused_turf() - var/list/in_range = get_mobs_and_objs_in_view_fast(T, world.view, 0) - var/list/mobs_to_relay = in_range["mobs"] - - for(var/thing in mobs_to_relay) - var/mob/mob = thing - var/message = mob.combine_message(message_pieces, verb, M) - var/name_used = M.GetVoice() - var/rendered = null - rendered = "[name_used] [message]" - mob.show_message(rendered, 2) - - ..() - -// Returns the position that an atom that's hopefully on the other side of the portal would be if it were really there. -// Z levels not taken into account. -/obj/effect/map_effect/portal/master/proc/get_apparent_position(atom/A) - if(!counterpart) - return null - - var/turf/true_turf = get_turf(A) - var/obj/effect/map_effect/portal/master/other_master = counterpart - - var/in_vis_contents = FALSE - for(var/thing in other_master.portal_lines + other_master) - var/obj/effect/map_effect/portal/P = thing - if(P in true_turf.vis_locs) - in_vis_contents = TRUE - break - - if(!in_vis_contents) - return null // Not in vision of the other portal. - - var/turf/their_focus = counterpart.get_focused_turf() - var/turf/our_focus = get_focused_turf() - - var/relative_x = (true_turf.x - our_focus.x) - relative_x += SIGN(relative_x) - var/relative_y = (true_turf.y - our_focus.y) - relative_y += SIGN(relative_y) - - return new /datum/position(their_focus.x + relative_x, their_focus.y + relative_y, our_focus.z) - - -/obj/effect/map_effect/portal/master/side_a - name = "portal master A" - icon_state = "portal_side_a" -// color = "#00FF00" - -/obj/effect/map_effect/portal/master/side_b - name = "portal master B" - icon_state = "portal_side_b" -// color = "#FF0000" - - - -// Portal lines extend out from the sides of portal masters, -// They let portals be longer than 1x1. -// Both sides MUST be the same length, meaning if side A is 1x3, side B must also be 1x3. -/obj/effect/map_effect/portal/line - name = "portal line" - var/obj/effect/map_effect/portal/master/my_master = null - -/obj/effect/map_effect/portal/line/Destroy() - if(my_master) - my_master.portal_lines -= src - my_master = null - return ..() - -/obj/effect/map_effect/portal/line/side_a - name = "portal line A" - icon_state = "portal_line_side_a" - -/obj/effect/map_effect/portal/line/side_b - name = "portal line B" +GLOBAL_LIST_EMPTY(all_portal_masters) + +/* + +Portal map effects allow a mapper to join two distant places together, while looking somewhat seamlessly connected. +This can allow for very strange PoIs that twist and turn in what appear to be physically impossible ways. + +Portals do have some specific requirements when mapping them in; + - There must by one, and only one `/obj/effect/map_effect/portal/master` for each side of a portal. + - Both sides need to have matching `portal_id`s in order to link to each other. + - Each side must face opposite directions, e.g. if side A faces SOUTH, side B must face NORTH. + - Each side must have the same orientation, e.g. horizontal on both sides, or vertical on both sides. + - Portals can be made to be longer than 1x1 with `/obj/effect/map_effect/portal/line`s, + but both sides must have the same length. + - If portal lines are added, they must form a straight line and be next to a portal master or another portal line. + - If portal lines are used, both portal masters should be in the same relative position among the lines. + E.g. both being on the left most side on a horizontal row. + +Portals also have some limitations to be aware of when mapping. Some of these are not an issue if you're trying to make an 'obvious' portal; + - The objects seen through portals are purely visual, which has many implications, + such as simple_mob AIs being blind to mobs on the other side of portals. + - Objects on the other side of a portal can be interacted with if the interaction has no range limitation, + or the distance between the two portal sides happens to be less than the interaction max range. Examine will probably work, + while picking up an item that appears to be next to you will fail. + - Sounds currently are not carried across portals. + - Mismatched lighting between each portal end can make the portal look obvious. + - Portals look weird when observing as a ghost, or otherwise when able to see through walls. Meson vision will also spoil the illusion. + - Walls that change icons based on neightboring walls can give away that a portal is nearby if both sides don't have a similar transition. + - Projectiles that pass through portals will generally work as intended, however aiming and firing upon someone on the other side of a portal + will likely be weird due to the click targeting the real position of the thing clicked instead of the apparent position. + Thrown objects suffer a similar fate. + - The tiles that are visually shown across a portal are determined based on visibility at the time of portal initialization, + and currently don't update, meaning that opacity changes are not reflected, e.g. a wall is deconstructed, or an airlock is opened. + - There is currently a small but somewhat noticable pause in mob movement when moving across a portal, + as a result of the mob's glide animation being inturrupted by a teleport. + - Gas is not transferred through portals, and ZAS is oblivious to them. + +A lot of those limitations can potentially be solved with some more work. Otherwise, portals work best in static environments like Points of Interest, +when portals are shortly lived, or when portals are made to be obvious with special effects. +*/ + +/obj/effect/map_effect/portal + name = "portal subtype" + invisibility = 0 + opacity = TRUE + plane = TURF_PLANE + layer = ABOVE_TURF_LAYER + appearance_flags = PIXEL_SCALE|KEEP_TOGETHER // Removed TILE_BOUND so things not visible on the other side stay hidden from the viewer. + + var/obj/effect/map_effect/portal/counterpart = null // The portal line or master that this is connected to, on the 'other side'. + + // Information used to apply `pixel_[x|y]` offsets so that the visuals line up. + // Set automatically by `calculate_dimensions()`. + var/total_height = 0 // Measured in tiles. + var/total_width = 0 + + var/portal_distance_x = 0 // How far the portal is from the left edge, in tiles. + var/portal_distance_y = 0 // How far the portal is from the top edge. + +/obj/effect/map_effect/portal/Destroy() + vis_contents = null + if(counterpart) + counterpart.counterpart = null // Disconnect our counterpart from us + counterpart = null // Now disconnect us from them. + return ..() + +// Called when something touches the portal, and usually teleports them to the other side. +/obj/effect/map_effect/portal/Crossed(atom/movable/AM) + if(AM.is_incorporeal()) + return + ..() + if(!AM) + return + if(!counterpart) + return + + go_through_portal(AM) + + +/obj/effect/map_effect/portal/proc/go_through_portal(atom/movable/AM) + // TODO: Find a way to fake the glide or something. + if(isliving(AM)) + var/mob/living/L = AM + if(L.pulling) + var/atom/movable/pulled = L.pulling + L.stop_pulling() + // For some reason, trying to put the pulled object behind the person makes the drag stop and it doesn't even move to the other side. + // pulled.forceMove(get_turf(counterpart)) + pulled.forceMove(counterpart.get_focused_turf()) + L.forceMove(counterpart.get_focused_turf()) + L.start_pulling(pulled) + else + L.forceMove(counterpart.get_focused_turf()) + else + AM.forceMove(counterpart.get_focused_turf()) + +// 'Focused turf' is the turf directly in front of a portal, +// and it is used both as the destination when crossing, as well as the PoV for visuals. +/obj/effect/map_effect/portal/proc/get_focused_turf() + return get_step(get_turf(src), dir) + +// Determines the size of the block of turfs inside `vis_contents`, and where the portal is in relation to that. +/obj/effect/map_effect/portal/proc/calculate_dimensions() + var/highest_x = 0 + var/lowest_x = 0 + + var/highest_y = 0 + var/lowest_y = 0 + + // First pass is for finding the top right corner. + for(var/thing in vis_contents) + var/turf/T = thing + if(T.x > highest_x) + highest_x = T.x + if(T.y > highest_y) + highest_y = T.y + + lowest_x = highest_x + lowest_y = highest_y + + // Second one is for the bottom left corner. + for(var/thing in vis_contents) + var/turf/T = thing + if(T.x < lowest_x) + lowest_x = T.x + if(T.y < lowest_y) + lowest_y = T.y + + // Now calculate the dimensions. + total_width = (highest_x - lowest_x) + 1 + total_height = (highest_y - lowest_y) + 1 + + // Find how far the portal is from the edges. + var/turf/focused_T = counterpart.get_focused_turf() + portal_distance_x = lowest_x - focused_T.x + portal_distance_y = lowest_y - focused_T.y + + +// Portal masters manage everything else involving portals. +// This is the base type. Use `/side_a` or `/side_b` with matching IDs for actual portals. +/obj/effect/map_effect/portal/master + name = "portal master" + show_messages = TRUE // So portals can hear and see, and relay to the other side. + var/portal_id = "test" // For a portal to be made, both the A and B sides need to share the same ID value. + var/list/portal_lines = list() + +/obj/effect/map_effect/portal/master/Initialize() + GLOB.all_portal_masters += src + find_lines() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/effect/map_effect/portal/master/LateInitialize() + find_counterparts() + make_visuals() + apply_offset() + +/obj/effect/map_effect/portal/master/Destroy() + GLOB.all_portal_masters -= src + for(var/thing in portal_lines) + qdel(thing) + return ..() + +/obj/effect/map_effect/portal/master/proc/find_lines() + var/list/dirs_to_search = list( turn(dir, 90), turn(dir, -90) ) + + for(var/dir_to_search in dirs_to_search) + var/turf/current_T = get_turf(src) + while(current_T) + current_T = get_step(current_T, dir_to_search) + var/obj/effect/map_effect/portal/line/line = locate() in current_T + if(line) + portal_lines += line + line.my_master = src + else + break + +// Connects both sides of a portal together. +/obj/effect/map_effect/portal/master/proc/find_counterparts() + for(var/thing in GLOB.all_portal_masters) + var/obj/effect/map_effect/portal/master/M = thing + if(M == src) + continue + if(M.counterpart) + continue + + if(M.portal_id == src.portal_id) + counterpart = M + M.counterpart = src + if(portal_lines.len) + for(var/i = 1 to portal_lines.len) + var/obj/effect/map_effect/portal/line/our_line = portal_lines[i] + var/obj/effect/map_effect/portal/line/their_line = M.portal_lines[i] + our_line.counterpart = their_line + their_line.counterpart = our_line + break + + if(!counterpart) + crash_with("Portal master [type] ([x],[y],[z]) could not find another portal master with a matching portal_id ([portal_id]).") + +/obj/effect/map_effect/portal/master/proc/make_visuals() + var/list/observed_turfs = list() + for(var/thing in portal_lines + src) + var/obj/effect/map_effect/portal/P = thing + P.name = null + P.icon_state = null + + if(!P.counterpart) + return + + var/turf/T = P.counterpart.get_focused_turf() + P.vis_contents += T + + var/list/things = dview(world.view, T) + for(var/turf/turf in things) + if(get_dir(turf, T) & P.dir) + if(turf in observed_turfs) // Avoid showing the same turf twice or more for improved performance. + continue + + P.vis_contents += turf + observed_turfs += turf + + P.calculate_dimensions() + +// Shifts the portal's pixels in order to line up properly, as BYOND offsets the sprite when it holds multiple turfs inside `vis_contents`. +// This undos the shift that BYOND did. +/obj/effect/map_effect/portal/master/proc/apply_offset() + for(var/thing in portal_lines + src) + var/obj/effect/map_effect/portal/P = thing + + P.pixel_x = WORLD_ICON_SIZE * P.portal_distance_x + P.pixel_y = WORLD_ICON_SIZE * P.portal_distance_y + +// Allows portals to transfer emotes. +// Only portal masters do this to avoid flooding the other side with duplicate messages. +/obj/effect/map_effect/portal/master/see_emote(mob/M, text) + if(!counterpart) + return + var/turf/T = counterpart.get_focused_turf() + var/list/in_range = get_mobs_and_objs_in_view_fast(T, world.view, 0) + var/list/mobs_to_relay = in_range["mobs"] + + for(var/thing in mobs_to_relay) + var/mob/mob = thing + var/rendered = "[text]" + mob.show_message(rendered) + + ..() + +// Allows portals to transfer visible messages. +/obj/effect/map_effect/portal/master/show_message(msg, type, alt, alt_type) + if(!counterpart) + return + var/rendered = "[msg]" + var/turf/T = counterpart.get_focused_turf() + var/list/in_range = get_mobs_and_objs_in_view_fast(T, world.view, 0) + var/list/mobs_to_relay = in_range["mobs"] + + for(var/thing in mobs_to_relay) + var/mob/mob = thing + mob.show_message(rendered) + + ..() + +// Allows portals to transfer speech. +/obj/effect/map_effect/portal/master/hear_talk(mob/M, list/message_pieces, verb) + if(!counterpart) + return + var/turf/T = counterpart.get_focused_turf() + var/list/in_range = get_mobs_and_objs_in_view_fast(T, world.view, 0) + var/list/mobs_to_relay = in_range["mobs"] + + for(var/thing in mobs_to_relay) + var/mob/mob = thing + var/message = mob.combine_message(message_pieces, verb, M) + var/name_used = M.GetVoice() + var/rendered = null + rendered = "[name_used] [message]" + mob.show_message(rendered, 2) + + ..() + +// Returns the position that an atom that's hopefully on the other side of the portal would be if it were really there. +// Z levels not taken into account. +/obj/effect/map_effect/portal/master/proc/get_apparent_position(atom/A) + if(!counterpart) + return null + + var/turf/true_turf = get_turf(A) + var/obj/effect/map_effect/portal/master/other_master = counterpart + + var/in_vis_contents = FALSE + for(var/thing in other_master.portal_lines + other_master) + var/obj/effect/map_effect/portal/P = thing + if(P in true_turf.vis_locs) + in_vis_contents = TRUE + break + + if(!in_vis_contents) + return null // Not in vision of the other portal. + + var/turf/their_focus = counterpart.get_focused_turf() + var/turf/our_focus = get_focused_turf() + + var/relative_x = (true_turf.x - our_focus.x) + relative_x += SIGN(relative_x) + var/relative_y = (true_turf.y - our_focus.y) + relative_y += SIGN(relative_y) + + return new /datum/position(their_focus.x + relative_x, their_focus.y + relative_y, our_focus.z) + + +/obj/effect/map_effect/portal/master/side_a + name = "portal master A" + icon_state = "portal_side_a" +// color = "#00FF00" + +/obj/effect/map_effect/portal/master/side_b + name = "portal master B" + icon_state = "portal_side_b" +// color = "#FF0000" + + + +// Portal lines extend out from the sides of portal masters, +// They let portals be longer than 1x1. +// Both sides MUST be the same length, meaning if side A is 1x3, side B must also be 1x3. +/obj/effect/map_effect/portal/line + name = "portal line" + var/obj/effect/map_effect/portal/master/my_master = null + +/obj/effect/map_effect/portal/line/Destroy() + if(my_master) + my_master.portal_lines -= src + my_master = null + return ..() + +/obj/effect/map_effect/portal/line/side_a + name = "portal line A" + icon_state = "portal_line_side_a" + +/obj/effect/map_effect/portal/line/side_b + name = "portal line B" icon_state = "portal_line_side_b" \ No newline at end of file diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index f20e340f34..fd9767dd87 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -22,15 +22,26 @@ to_chat(user, "ERROR ERROR ERROR") /obj/item/device/aicard/attack_self(mob/user) + tgui_interact(user) - ui_interact(user) +/obj/item/device/aicard/tgui_interact(mob/user, datum/tgui/ui = null, datum/tgui_state/custom_state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AICard", "[name]") // 600, 394 + ui.open() + if(custom_state) + ui.set_state(custom_state) -/obj/item/device/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = inventory_state) +/obj/item/device/aicard/tgui_state(mob/user) + return GLOB.tgui_inventory_state + +/obj/item/device/aicard/tgui_data(mob/user) var/data[0] + data["has_ai"] = carded_ai != null if(carded_ai) data["name"] = carded_ai.name - data["hardware_integrity"] = carded_ai.hardware_integrity() + data["integrity"] = carded_ai.hardware_integrity() data["backup_capacitor"] = carded_ai.backup_capacitor() data["radio"] = !carded_ai.aiRadio.disabledAi data["wireless"] = !carded_ai.control_disabled @@ -38,52 +49,42 @@ data["flushing"] = flush var/laws[0] - for(var/datum/ai_law/AL in carded_ai.laws.all_laws()) - laws[++laws.len] = list("index" = AL.get_index(), "law" = sanitize(AL.law)) + for(var/datum/ai_law/law in carded_ai.laws.all_laws()) + if(law in carded_ai.laws.ion_laws) // If we're an ion law, give it an ion index code + laws.Add(ionnum() + ". " + law.law) + else + laws.Add(num2text(law.get_index()) + ". " + law.law) data["laws"] = laws - data["has_laws"] = laws.len + data["has_laws"] = length(carded_ai.laws.all_laws()) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "aicard.tmpl", "[name]", 600, 400, state = state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/obj/item/device/aicard/Topic(href, href_list, state) +/obj/item/device/aicard/tgui_act(action, params) if(..()) - return 1 + return TRUE if(!carded_ai) - return 1 + return var/user = usr - if (href_list["wipe"]) - var/confirm = alert("Are you sure you want to disable this core's power? This cannot be undone once started.", "Confirm Shutdown", "No", "Yes") - if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE)) + switch(action) + if("wipe") + msg_admin_attack("[key_name_admin(user)] wiped [key_name_admin(AI)] with \the [src].") add_attack_logs(user,carded_ai,"Purged from AI Card") - flush = 1 - carded_ai.suiciding = 1 - to_chat(carded_ai, "Your power has been disabled!") - while (carded_ai && carded_ai.stat != DEAD) - if(carded_ai.deployed_shell && prob(carded_ai.oxyloss)) //You feel it creeping? Eventually will reach 100, resulting in the second half of the AI's remaining life being lonely. - carded_ai.disconnect_shell("Disconnecting from remote shell due to insufficent power.") - carded_ai.adjustOxyLoss(2) - carded_ai.updatehealth() - sleep(10) - flush = 0 - if (href_list["radio"]) - carded_ai.aiRadio.disabledAi = text2num(href_list["radio"]) - to_chat(carded_ai, "Your Subspace Transceiver has been [carded_ai.aiRadio.disabledAi ? "disabled" : "enabled"]!") - to_chat(user, "You [carded_ai.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.") - if (href_list["wireless"]) - carded_ai.control_disabled = text2num(href_list["wireless"]) - to_chat(carded_ai, "Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!") - to_chat(user, "You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.") - if(carded_ai.control_disabled && carded_ai.deployed_shell) - carded_ai.disconnect_shell("Disconnecting from remote shell due to [src] wireless access interface being disabled.") - update_icon() - return 1 + INVOKE_ASYNC(src, .proc/wipe_ai) + if("radio") + carded_ai.aiRadio.disabledAi = !carded_ai.aiRadio.disabledAi + to_chat(carded_ai, "Your Subspace Transceiver has been [carded_ai.aiRadio.disabledAi ? "disabled" : "enabled"]!") + to_chat(user, "You [carded_ai.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.") + if("wireless") + carded_ai.control_disabled = !carded_ai.control_disabled + to_chat(carded_ai, "Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!") + to_chat(user, "You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.") + if(carded_ai.control_disabled && carded_ai.deployed_shell) + carded_ai.disconnect_shell("Disconnecting from remote shell due to [src] wireless access interface being disabled.") + update_icon() + + return TRUE /obj/item/device/aicard/update_icon() overlays.Cut() @@ -168,3 +169,17 @@ var/obj/item/weapon/rig/rig = src.get_rig() if(istype(rig)) rig.forced_move(direction, user) + +/obj/item/device/aicard/proc/wipe_ai() + var/mob/living/silicon/ai/AI = carded_ai + flush = TRUE + AI.suiciding = TRUE + to_chat(AI, "Your power has been disabled!") + while(AI && AI.stat != DEAD) + // This is absolutely evil and I love it. + if(AI.deployed_shell && prob(AI.oxyloss)) //You feel it creeping? Eventually will reach 100, resulting in the second half of the AI's remaining life being lonely. + AI.disconnect_shell("Disconnecting from remote shell due to insufficent power.") + AI.adjustOxyLoss(2) + AI.updatehealth() + sleep(10) + flush = FALSE \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 47de7ff7dd..f5c3918fc9 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -382,7 +382,7 @@ return -/obj/item/device/radio/headset/proc/recalculateChannels(var/setDescription = 0) +/obj/item/device/radio/headset/recalculateChannels(var/setDescription = 0) src.channels = list() src.translate_binary = 0 src.translate_hive = 0 diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 47e71092cf..210b93f1b0 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -37,12 +37,14 @@ var/global/list/default_medbay_channels = list( var/frequency = PUB_FREQ //common chat var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies var/canhear_range = 3 // the range which mobs can hear this radio from + var/loudspeaker = TRUE // Allows borgs to disable canhear_range. var/datum/wires/radio/wires = null var/b_stat = 0 var/broadcasting = 0 var/listening = 1 var/list/channels = list() //see communications.dm for full list. First channel is a "default" for :h var/subspace_transmission = 0 + var/subspace_switchable = FALSE var/adhoc_fallback = FALSE //Falls back to 'radio' mode if subspace not available var/syndie = 0//Holder to see if it's a syndicate encrypted radio var/centComm = 0//Holder to see if it's a CentCom encrypted radio @@ -133,6 +135,8 @@ var/global/list/default_medbay_channels = list( if(!found) testing("A radio [src] at [x],[y],[z] specified bluespace prelink IDs, but the machines with corresponding IDs ([bs_tx_preload_id], [bs_rx_preload_id]) couldn't be found.") +/obj/item/device/radio/proc/recalculateChannels() + return /obj/item/device/radio/attack_self(mob/user as mob) user.set_machine(src) @@ -145,15 +149,31 @@ var/global/list/default_medbay_channels = list( if(b_stat) wires.Interact(user) - return ui_interact(user) + return tgui_interact(user) -/obj/item/device/radio/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/item/device/radio/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nano_ui/master_ui, datum/topic_state/state) + log_runtime(EXCEPTION("Warning: [user] attempted to call ui_interact on radio [src] [type]. This is deprecated. Please update the caller to tgui_interact.")) + +/obj/item/device/radio/Topic(href, href_list) + if(href_list["track"]) + log_runtime(EXCEPTION("Warning: Topic() was improperly called on radio [src] [type], with the track href and \[[href] [json_encode(href_list)]]. Please update the caller to use tgui_act.")) + . = ..() + +/obj/item/device/radio/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Radio", name) + ui.open() + +/obj/item/device/radio/tgui_data(mob/user) var/data[0] - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) data["rawfreq"] = num2text(frequency) + data["listening"] = listening + data["broadcasting"] = broadcasting + data["subspace"] = subspace_transmission + data["subspaceSwitchable"] = subspace_switchable + data["loudspeaker"] = loudspeaker data["mic_cut"] = (wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL)) data["spk_cut"] = (wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL)) @@ -161,21 +181,16 @@ var/global/list/default_medbay_channels = list( var/list/chanlist = list_channels(user) if(islist(chanlist) && chanlist.len) data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len + else + data["chan_list"] = null if(syndie) data["useSyndMode"] = 1 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430) - ui.set_initial_data(data) - ui.open() + data["minFrequency"] = PUBLIC_LOW_FREQ + data["maxFrequency"] = PUBLIC_HIGH_FREQ -/obj/item/device/radio/CouldUseTopic(var/mob/user) - ..() - if(iscarbon(user)) - playsound(src, "button", 10) + return data /obj/item/device/radio/proc/list_channels(var/mob/user) return list_internal_channels(user) @@ -187,7 +202,7 @@ var/global/list/default_medbay_channels = list( var/chan_stat = channels[ch_name] var/listening = !!(chan_stat & FREQ_LISTENING) != 0 - dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "chan_span" = frequency_span_class(radiochannels[ch_name])))) + dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "freq" = radiochannels[ch_name]))) return dat @@ -195,7 +210,7 @@ var/global/list/default_medbay_channels = list( var/dat[0] for(var/internal_chan in internal_channels) if(has_channel_access(user, internal_chan)) - dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "chan_span" = frequency_span_class(text2num(internal_chan))))) + dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "freq" = text2num(internal_chan)))) return dat @@ -233,50 +248,61 @@ var/global/list/default_medbay_channels = list( return STATUS_CLOSE return ..() -/obj/item/device/radio/Topic(href, href_list) +/obj/item/device/radio/tgui_act(action, params) if(..()) return TRUE - usr.set_machine(src) - if (href_list["track"]) - var/mob/target = locate(href_list["track"]) - var/mob/living/silicon/ai/A = locate(href_list["track2"]) - if(A && target) - A.ai_actual_track(target) - . = 1 - - else if (href_list["freq"]) - var/new_frequency = (frequency + text2num(href_list["freq"])) - if ((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) - new_frequency = sanitize_frequency(new_frequency) - set_frequency(new_frequency) - if(hidden_uplink) - if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) - usr << browse(null, "window=radio") - . = 1 - else if (href_list["talk"]) - ToggleBroadcast() - . = 1 - else if (href_list["listen"]) - var/chan_name = href_list["ch_name"] - if (!chan_name) + switch(action) + if("setFrequency") + var/new_frequency = (text2num(params["freq"])) + if((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) + new_frequency = sanitize_frequency(new_frequency) + set_frequency(new_frequency) + if(hidden_uplink) + if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) + usr << browse(null, "window=radio") + . = TRUE + if("broadcast") + ToggleBroadcast() + . = TRUE + if("listen") ToggleReception() - else - if (channels[chan_name] & FREQ_LISTENING) + . = TRUE + if("channel") + var/chan_name = params["channel"] + if(channels[chan_name] & FREQ_LISTENING) channels[chan_name] &= ~FREQ_LISTENING else channels[chan_name] |= FREQ_LISTENING - . = 1 - else if(href_list["spec_freq"]) - var freq = href_list["spec_freq"] - if(has_channel_access(usr, freq)) - set_frequency(text2num(freq)) - . = 1 - if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk - return TRUE + . = TRUE + if("specFreq") + var/freq = params["channel"] + if(has_channel_access(usr, freq)) + set_frequency(text2num(freq)) + . = TRUE + if("subspace") + if(subspace_switchable) + subspace_transmission = !subspace_transmission + if(!subspace_transmission) + channels = list() + to_chat(usr, "Subspace Transmission is disabled") + else + recalculateChannels() + to_chat(usr, "Subspace Transmission is enabled") + . = TRUE + if("toggleLoudspeaker") + if(!subspace_switchable) + return + loudspeaker = !loudspeaker - if(.) - SSnanoui.update_uis(src) + if(loudspeaker) + to_chat(usr, "Loadspeaker enabled.") + else + to_chat(usr, "Loadspeaker disabled.") + . = TRUE + + if(. && iscarbon(usr)) + playsound(src, "button", 10) GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer) /obj/item/device/radio/proc/autosay(var/message, var/from, var/channel, var/list/zlevels) //BS12 EDIT @@ -569,10 +595,9 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer) return canhear_range /obj/item/device/radio/proc/send_hear(freq, level) - var/range = receive_range(freq, level) - if(range > -1) - return get_mobs_or_objects_in_view(canhear_range, src) + if(range > -1 && loudspeaker) + return get_mobs_or_objects_in_view(range, src) /obj/item/device/radio/examine(mob/user) @@ -616,11 +641,11 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer) /obj/item/device/radio/borg var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks var/obj/item/device/encryptionkey/keyslot = null//Borg radios can handle a single encryption key - var/shut_up = 1 icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component. icon_state = "radio" canhear_range = 0 - subspace_transmission = 1 + subspace_transmission = TRUE + subspace_switchable = TRUE /obj/item/device/radio/borg/Destroy() myborg = null @@ -678,7 +703,7 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer) return -/obj/item/device/radio/borg/proc/recalculateChannels() +/obj/item/device/radio/borg/recalculateChannels() src.channels = list() src.syndie = 0 @@ -710,71 +735,6 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer) return -/obj/item/device/radio/borg/Topic(href, href_list) - if(..()) - return TRUE - if (href_list["mode"]) - var/enable_subspace_transmission = text2num(href_list["mode"]) - if(enable_subspace_transmission != subspace_transmission) - subspace_transmission = !subspace_transmission - if(subspace_transmission) - to_chat(usr, "Subspace Transmission is enabled") - else - to_chat(usr, "Subspace Transmission is disabled") - - if(subspace_transmission == 0)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled - channels = list() - else - recalculateChannels() - . = 1 - if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. - var/do_shut_up = text2num(href_list["shutup"]) - if(do_shut_up != shut_up) - shut_up = !shut_up - if(shut_up) - canhear_range = 0 - to_chat(usr, "Loadspeaker disabled.") - else - canhear_range = 3 - to_chat(usr, "Loadspeaker enabled.") - . = 1 - - if(.) - SSnanoui.update_uis(src) - -/obj/item/device/radio/borg/interact(mob/user as mob) - if(!on) - return - - . = ..() - -/obj/item/device/radio/borg/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) - - var/list/chanlist = list_channels(user) - if(islist(chanlist) && chanlist.len) - data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len - - if(syndie) - data["useSyndMode"] = 1 - - data["has_loudspeaker"] = 1 - data["loudspeaker"] = !shut_up - data["has_subspace"] = 1 - data["subspace"] = subspace_transmission - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430) - ui.set_initial_data(data) - ui.open() - /obj/item/device/radio/proc/config(op) if(radio_controller) for (var/ch_name in channels) diff --git a/code/game/objects/items/weapons/RPD_vr.dm b/code/game/objects/items/weapons/RPD_vr.dm index 9ae806f63c..b3b3507586 100644 --- a/code/game/objects/items/weapons/RPD_vr.dm +++ b/code/game/objects/items/weapons/RPD_vr.dm @@ -1,8 +1,11 @@ -#define PAINT_MODE -2 -#define EATING_MODE -1 -#define ATMOS_MODE 0 -#define DISPOSALS_MODE 1 -#define TRANSIT_MODE 2 +#define ATMOS_CATEGORY 0 +#define DISPOSALS_CATEGORY 1 +#define TRANSIT_CATEGORY 2 + +#define BUILD_MODE (1<<0) +#define WRENCH_MODE (1<<1) +#define DESTROY_MODE (1<<2) +#define PAINT_MODE (1<<3) /obj/item/weapon/pipe_dispenser name = "Rapid Piping Device (RPD)" @@ -22,18 +25,16 @@ w_class = ITEMSIZE_NORMAL matter = list(MAT_STEEL = 50000, MAT_GLASS = 25000) var/datum/effect/effect/system/spark_spread/spark_system - var/mode = ATMOS_MODE var/p_dir = NORTH // Next pipe will be built with this dir var/p_flipped = FALSE // If the next pipe should be built flipped var/paint_color = "grey" // Pipe color index for next pipe painted/built. - var/screen = ATMOS_MODE // Starts on the atmos tab. + var/category = ATMOS_CATEGORY var/piping_layer = PIPING_LAYER_DEFAULT - var/wrench_mode = FALSE var/obj/item/weapon/tool/wrench/tool var/datum/pipe_recipe/recipe // pipe recipie selected for display/construction var/static/datum/pipe_recipe/first_atmos var/static/datum/pipe_recipe/first_disposal - var/static/datum/asset/spritesheet/pipes/icon_assets + var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE var/static/list/pipe_layers = list( "Regular" = PIPING_LAYER_REGULAR, "Supply" = PIPING_LAYER_SUPPLY, @@ -51,10 +52,10 @@ /obj/item/weapon/pipe_dispenser/proc/SetupPipes() if(!first_atmos) - first_atmos = atmos_pipe_recipes[atmos_pipe_recipes[1]][1] + first_atmos = GLOB.atmos_pipe_recipes[GLOB.atmos_pipe_recipes[1]][1] recipe = first_atmos if(!first_disposal) - first_disposal = disposal_pipe_recipes[disposal_pipe_recipes[1]][1] + first_disposal = GLOB.disposal_pipe_recipes[GLOB.disposal_pipe_recipes[1]][1] /obj/item/weapon/pipe_dispenser/Destroy() qdel_null(spark_system) @@ -69,170 +70,97 @@ return(BRUTELOSS) /obj/item/weapon/pipe_dispenser/attack_self(mob/user) - src.interact(user) + tgui_interact(user) -// TODO - Wouldn't it be nice to have nanoui? -/obj/item/weapon/pipe_dispenser/interact(mob/user) +/obj/item/weapon/pipe_dispenser/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/pipes), + ) + +/obj/item/weapon/pipe_dispenser/tgui_interact(mob/user, datum/tgui/ui) SetupPipes() - if(!icon_assets) - icon_assets = get_asset_datum(/datum/asset/spritesheet/pipes) - icon_assets.send(user) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "RapidPipeDispenser", name) + ui.open() - var/list/lines = list() - if(mode >= ATMOS_MODE) - lines += "

Direction:

" - switch(recipe.dirtype) +/obj/item/weapon/pipe_dispenser/tgui_data(mob/user) + var/list/data = list( + "category" = category, + "piping_layer" = piping_layer, + "pipe_layers" = pipe_layers, + "preview_rows" = recipe.get_preview(p_dir), + "categories" = list(), + "selected_color" = paint_color, + "paint_colors" = pipe_colors, + "mode" = mode + ) - if(PIPE_STRAIGHT) // Straight, N-S, W-E - lines += render_dir_img(recipe.icon_state,user,NORTH,"Vertical","↕") - lines += render_dir_img(recipe.icon_state,user,EAST,"Horizontal","↔") + var/list/recipes + switch(category) + if(ATMOS_CATEGORY) + recipes = GLOB.atmos_pipe_recipes + if(DISPOSALS_CATEGORY) + recipes = GLOB.disposal_pipe_recipes + // if(TRANSIT_CATEGORY) + // recipes = transit_tube_recipes + for(var/c in recipes) + var/list/cat = recipes[c] + var/list/r = list() + for(var/i in 1 to cat.len) + var/datum/pipe_recipe/info = cat[i] + r += list(list("pipe_name" = info.name, "pipe_index" = i, "selected" = (info == recipe))) + data["categories"] += list(list("cat_name" = c, "recipes" = r)) - if(PIPE_BENDABLE) // Bent, N-W, N-E etc - lines += render_dir_img(recipe.icon_state,user,NORTH,"Vertical","↕") - lines += render_dir_img(recipe.icon_state,user,EAST,"Horizontal","↔") - lines += "
" - lines += render_dir_img(recipe.icon_state,user,NORTHWEST,"West to North","╝") - lines += render_dir_img(recipe.icon_state,user,NORTHEAST,"North to East","╚") - lines += render_dir_img(recipe.icon_state,user,SOUTHWEST,"South to West","╗") - lines += render_dir_img(recipe.icon_state,user,SOUTHEAST,"East to South","╔") + return data - if(PIPE_TRINARY) // Manifold - lines += render_dir_img(recipe.icon_state,user,NORTH,"West South East","╦") - lines += render_dir_img(recipe.icon_state,user,EAST,"North West South","╣") - lines += render_dir_img(recipe.icon_state,user,SOUTH,"East North West","╩") - lines += render_dir_img(recipe.icon_state,user,WEST,"South East North","╠") - - if(PIPE_TRIN_M) // Mirrored ones - //each mirror icon is 45 anticlockwise from it's real direction - lines += render_dir_img(recipe.icon_state,user,NORTH,"West South East","╦") - lines += render_dir_img(recipe.icon_state,user,EAST,"North West South","╣") - lines += render_dir_img(recipe.icon_state,user,SOUTH,"East North West","╩") - lines += render_dir_img(recipe.icon_state,user,WEST,"South East North","╠") - lines += "
" - lines += render_dir_img(recipe.icon_state_m,user,SOUTH,"West South East","╦", 1) - lines += render_dir_img(recipe.icon_state_m,user,WEST,"South East North","╠", 1) - lines += render_dir_img(recipe.icon_state_m,user,NORTH,"East North West","╩", 1) - lines += render_dir_img(recipe.icon_state_m,user,EAST,"North West South","╣", 1) - - if(PIPE_DIRECTIONAL) // Stuff with four directions - includes pumps etc. - lines += render_dir_img(recipe.icon_state,user,NORTH,"North","↑") - lines += render_dir_img(recipe.icon_state,user,EAST,"East","→") - lines += render_dir_img(recipe.icon_state,user,SOUTH,"South","↓") - lines += render_dir_img(recipe.icon_state,user,WEST,"West","←") - - if(PIPE_ONEDIR) // Single icon_state (eg 4-way manifolds) - lines += render_dir_img(recipe.icon_state,user,SOUTH,"Pipe","↕") - lines += "
" - - if(mode == ATMOS_MODE || mode == PAINT_MODE) - lines += "

Color:

" - var/i = 0 - for(var/c in pipe_colors) - ++i - lines += "[c]" - if(i == 4) - lines += "
" - i = 0 - lines += "
" - - lines += "

Mode:

" - lines += "Lay Pipes" - lines += "Eat Pipes" - lines += "Paint Pipes" - lines += "
" - - lines += "

Category:

" - lines += "Atmospherics" - lines += "Disposals" - //lines += "Transit Tube" - lines += "
Wrench Mode" - lines += "
" - - if(screen == ATMOS_MODE) - for(var/category in atmos_pipe_recipes) - lines += "

[category]:

" - - if(category == "Pipes") - lines += "
" - for(var/pipename in pipe_layers) - var/pipelayer = pipe_layers[pipename] - lines += "[pipename] " - lines += "
" - lines += "
" - for(var/i in 1 to atmos_pipe_recipes[category].len) - var/datum/pipe_recipe/PI = atmos_pipe_recipes[category][i] - lines += "
" - lines += "[PI.name]" - lines += "
" - lines += "
" - else if(screen == DISPOSALS_MODE) - for(var/category in disposal_pipe_recipes) - lines += "

[category]:

" - for(var/i in 1 to disposal_pipe_recipes[category].len) - var/datum/pipe_recipe/PI = disposal_pipe_recipes[category][i] - lines += "
" - lines += "[PI.name]" - lines += "
" - lines += "
" - - var/dat = lines.Join() - var/datum/browser/popup = new(user, "rpd", name, 300, 800, src) - popup.set_content("[dat]") - popup.add_head_content(icon_assets.css_tag()) - popup.open() - -/obj/item/weapon/pipe_dispenser/Topic(href, href_list, state = global.inventory_state) +/obj/item/weapon/pipe_dispenser/tgui_act(action, params) SetupPipes() if(..()) - return 1 + return TRUE if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - return 1 - var/playeffect = TRUE // Do we spark the device - var/anyclicked = FALSE // Tells us if we need to refresh the window. - if(href_list["paint_color"]) - paint_color = href_list["paint_color"] - playeffect = FALSE - anyclicked = TRUE - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - anyclicked = TRUE - if(href_list["screen"]) - if(mode == screen) - mode = text2num(href_list["screen"]) - screen = text2num(href_list["screen"]) - switch(screen) - if(DISPOSALS_MODE) - recipe = first_disposal - if(ATMOS_MODE) - recipe = first_atmos - p_dir = NORTH - playeffect = FALSE - anyclicked = TRUE - if(href_list["piping_layer"]) - piping_layer = text2num(href_list["piping_layer"]) - playeffect = FALSE - anyclicked = TRUE - if(href_list["pipe_type"]) - recipe = all_pipe_recipes[href_list["category"]][text2num(href_list["pipe_type"])] - if(recipe.dirtype == PIPE_ONEDIR) // One hell of a hack for the fact that the image previews for the onedir types only show on the south, but the default pipe type is north. - p_dir = SOUTH // Did I fuck this up? Maybe. Or maybe it's just the icon files not being ready for an RPD. - else // If going to try and fix this hack, be aware the pipe dispensers might rely on pipes defaulting south instead of north. + return TRUE + var/playeffect = TRUE + switch(action) + if("color") + paint_color = params["paint_color"] + if("category") + category = text2num(params["category"]) + switch(category) + if(DISPOSALS_CATEGORY) + recipe = first_disposal + if(ATMOS_CATEGORY) + recipe = first_atmos + // if(TRANSIT_CATEGORY) + // recipe = first_transit p_dir = NORTH - p_flipped = FALSE - anyclicked = TRUE - if(href_list["dir"]) - p_dir = text2dir(href_list["dir"]) - p_flipped = text2num(href_list["flipped"]) - playeffect = FALSE - anyclicked = TRUE - if(href_list["switch_wrench"]) - wrench_mode = text2num(href_list["wrench_mode"]) - anyclicked = TRUE - if(anyclicked) - if(playeffect) - spark_system.start() - playsound(src, 'sound/effects/pop.ogg', 50, 0) - src.interact(usr) + playeffect = FALSE + if("piping_layer") + piping_layer = text2num(params["piping_layer"]) + playeffect = FALSE + // if("ducting_layer") + // ducting_layer = text2num(params["ducting_layer"]) + // playeffect = FALSE + if("pipe_type") + var/static/list/recipes + if(!recipes) + recipes = GLOB.disposal_pipe_recipes + GLOB.atmos_pipe_recipes + recipe = recipes[params["category"]][text2num(params["pipe_type"])] + p_dir = NORTH + if("setdir") + p_dir = text2dir(params["dir"]) + p_flipped = text2num(params["flipped"]) + playeffect = FALSE + if("mode") + var/n = text2num(params["mode"]) + if(mode & n) + mode &= ~n + else + mode |= n + if(playeffect) + spark_system.start() + playsound(get_turf(src), 'sound/effects/pop.ogg', 50, FALSE) + return TRUE /obj/item/weapon/pipe_dispenser/afterattack(atom/A, mob/user as mob, proximity) if(!user.IsAdvancedToolUser() || istype(A, /turf/space/transit) || !proximity) @@ -249,88 +177,89 @@ make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe)) var/can_make_pipe = (isturf(A) || is_type_in_typecache(A, make_pipe_whitelist)) - . = FALSE - switch(mode) //if we've gotten this var, the target is valid - if(PAINT_MODE) //Paint pipes - if(!istype(A, /obj/machinery/atmospherics/pipe)) - return ..() + var/can_destroy_pipe = istype(A, /obj/item/pipe) || istype(A, /obj/item/pipe_meter) || istype(A, /obj/structure/disposalconstruct) + + . = TRUE + if((mode & DESTROY_MODE) && can_destroy_pipe) + to_chat(user, "You start destroying a pipe...") + playsound(src, 'sound/machines/click.ogg', 50, 1) + if(do_after(user, 2, target = A)) + activate() + animate_deletion(A) + return + + if((mode & PAINT_MODE)) //Paint pipes + if(istype(A, /obj/machinery/atmospherics/pipe)) var/obj/machinery/atmospherics/pipe/P = A playsound(src, 'sound/machines/click.ogg', 50, 1) P.change_color(pipe_colors[paint_color]) user.visible_message("[user] paints \the [P] [paint_color].", "You paint \the [P] [paint_color].") return - if(EATING_MODE) //Eating pipes - if(!(istype(A, /obj/item/pipe) || istype(A, /obj/item/pipe_meter) || istype(A, /obj/structure/disposalconstruct))) - return ..() - to_chat(user, "You start destroying a pipe...") - playsound(src, 'sound/machines/click.ogg', 50, 1) - if(do_after(user, 2, target = A)) - activate() - animate_deletion(A) + if(mode & BUILD_MODE) //Making pipes + switch(category) + if(ATMOS_CATEGORY) + if(!can_make_pipe) + return ..() + playsound(src, 'sound/machines/click.ogg', 50, 1) + if(istype(recipe, /datum/pipe_recipe/meter)) + to_chat(user, "You start building a meter...") + if(do_after(user, 2, target = A)) + activate() + var/obj/item/pipe_meter/PM = new /obj/item/pipe_meter(get_turf(A)) + PM.setAttachLayer(queued_piping_layer) + if(mode & WRENCH_MODE) + do_wrench(PM, user) + else if(istype(recipe, /datum/pipe_recipe/pipe)) + var/datum/pipe_recipe/pipe/R = recipe + to_chat(user, "You start building a pipe...") + if(do_after(user, 2, target = A)) + activate() + var/obj/machinery/atmospherics/path = R.pipe_type + var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe + var/obj/item/pipe/P = new pipe_item_type(get_turf(A), path, queued_p_dir) - if(ATMOS_MODE) //Making pipes - if(!can_make_pipe) - return ..() - playsound(src, 'sound/machines/click.ogg', 50, 1) - if (istype(recipe, /datum/pipe_recipe/meter)) - to_chat(user, "You start building a meter...") - if(do_after(user, 2, target = A)) - activate() - var/obj/item/pipe_meter/PM = new /obj/item/pipe_meter(get_turf(A)) - PM.setAttachLayer(queued_piping_layer) - if(wrench_mode) - do_wrench(PM, user) - else if(istype(recipe, /datum/pipe_recipe/pipe)) - var/datum/pipe_recipe/pipe/R = recipe - to_chat(user, "You start building a pipe...") - if(do_after(user, 2, target = A)) - activate() - var/obj/machinery/atmospherics/path = R.pipe_type - var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe - var/obj/item/pipe/P = new pipe_item_type(get_turf(A), path, queued_p_dir) + P.update() + P.add_fingerprint(usr) + if(R.paintable) + P.color = pipe_colors[paint_color] + P.setPipingLayer(queued_piping_layer) + if(queued_p_flipped) + P.do_a_flip() + if(mode & WRENCH_MODE) + do_wrench(P, user) + else + build_effect(P) - P.update() - P.add_fingerprint(usr) - if (R.paintable) - P.color = pipe_colors[paint_color] - P.setPipingLayer(queued_piping_layer) - if(queued_p_flipped) - P.do_a_flip() - if(wrench_mode) - do_wrench(P, user) - else - build_effect(P) - - if(DISPOSALS_MODE) //Making disposals pipes - var/datum/pipe_recipe/disposal/R = recipe - if(!istype(R) || !can_make_pipe) - return ..() - A = get_turf(A) - if(istype(A, /turf/unsimulated)) - to_chat(user, "[src]'s error light flickers; there's something in the way!") - return - to_chat(user, "You start building a disposals pipe...") - playsound(src, 'sound/machines/click.ogg', 50, 1) - if(do_after(user, 4, target = A)) - var/obj/structure/disposalconstruct/C = new(A, R.pipe_type, queued_p_dir, queued_p_flipped, R.subtype) - - if(!C.can_place()) - to_chat(user, "There's not enough room to build that here!") - qdel(C) + if(DISPOSALS_CATEGORY) //Making disposals pipes + var/datum/pipe_recipe/disposal/R = recipe + if(!istype(R) || !can_make_pipe) + return ..() + A = get_turf(A) + if(istype(A, /turf/unsimulated)) + to_chat(user, "[src]'s error light flickers; there's something in the way!") return + to_chat(user, "You start building a disposals pipe...") + playsound(src, 'sound/machines/click.ogg', 50, 1) + if(do_after(user, 4, target = A)) + var/obj/structure/disposalconstruct/C = new(A, R.pipe_type, queued_p_dir, queued_p_flipped, R.subtype) - activate() + if(!C.can_place()) + to_chat(user, "There's not enough room to build that here!") + qdel(C) + return - C.add_fingerprint(usr) - C.update_icon() - if(wrench_mode) - do_wrench(C, user) - else - build_effect(C) + activate() - else - return ..() + C.add_fingerprint(usr) + C.update_icon() + if(mode & WRENCH_MODE) + do_wrench(C, user) + else + build_effect(C) + + else + return ..() /obj/item/weapon/pipe_dispenser/proc/build_effect(var/obj/P, var/time = 1.5) set waitfor = FALSE @@ -359,19 +288,11 @@ if(!resolved && tool && target) tool.afterattack(target,user,1) -/obj/item/weapon/pipe_dispenser/proc/render_dir_img(icon_state, user, _dir, title, noimg, flipped = FALSE) - var/dirtext = dir2text(_dir) - var/attrs = " style=\"height:34px;width:34px;display:inline-block\"" - if(_dir == p_dir && flipped == p_flipped) - attrs += " class=\"linkOn\"" - if(icon_state) - var/img_tag = icon_assets.icon_tag("[dirtext]-[icon_state]") - return "[img_tag]" - else - return "[noimg]" +#undef ATMOS_CATEGORY +#undef DISPOSALS_CATEGORY +#undef TRANSIT_CATEGORY - -#undef PAINT_MODE -#undef EATING_MODE -#undef ATMOS_MODE -#undef DISPOSALS_MODE +#undef BUILD_MODE +#undef WRENCH_MODE +#undef DESTROY_MODE +#undef PAINT_MODE \ No newline at end of file diff --git a/code/game/objects/items/weapons/cosmetics.dm b/code/game/objects/items/weapons/cosmetics.dm index 9435be7fb3..7150f7f556 100644 --- a/code/game/objects/items/weapons/cosmetics.dm +++ b/code/game/objects/items/weapons/cosmetics.dm @@ -96,17 +96,16 @@ w_class = ITEMSIZE_TINY icon = 'icons/obj/items.dmi' icon_state = "trinketbox" - var/list/ui_users = list() + var/datum/tgui_module/appearance_changer/mirror/coskit/M + +/obj/item/weapon/makeover/Initialize() + . = ..() + M = new(src, null) /obj/item/weapon/makeover/attack_self(mob/living/carbon/user as mob) if(ishuman(user)) to_chat(user, "You flip open \the [src] and begin to adjust your appearance.") - var/datum/nano_module/appearance_changer/AC = ui_users[user] - if(!AC) - AC = new(src, user) - AC.name = "SalonPro Porta-Makeover Deluxe™" - ui_users[user] = AC - AC.ui_interact(user) + M.tgui_interact(user) var/mob/living/carbon/human/H = user var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[O_EYES] if(istype(E)) diff --git a/code/game/objects/items/weapons/id cards/station_ids.dm b/code/game/objects/items/weapons/id cards/station_ids.dm index 5b1f6752ae..d701070aca 100644 --- a/code/game/objects/items/weapons/id cards/station_ids.dm +++ b/code/game/objects/items/weapons/id cards/station_ids.dm @@ -17,8 +17,7 @@ var/dna_hash = "\[UNSET\]" var/fingerprint_hash = "\[UNSET\]" var/sex = "\[UNSET\]" - var/icon/front - var/icon/side + var/front var/primary_color = rgb(0,0,0) // Obtained by eyedroppering the stripe in the middle of the card var/secondary_color = rgb(0,0,0) // Likewise for the oval in the top-left corner @@ -34,30 +33,27 @@ /obj/item/weapon/card/id/examine(mob/user) . = ..() if(in_range(user, src)) - show(user) //Not chat related + tgui_interact(user) //Not chat related else . += "It is too far away to read." /obj/item/weapon/card/id/proc/prevent_tracking() return 0 -/obj/item/weapon/card/id/proc/show(mob/user as mob) - if(front && side) - user << browse_rsc(front, "front.png") - user << browse_rsc(side, "side.png") - var/datum/browser/popup = new(user, "idcard", name, 600, 250) - popup.set_content(dat()) - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - return +/obj/item/weapon/card/id/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "IDCard", name) + ui.open() /obj/item/weapon/card/id/proc/update_name() name = "[src.registered_name]'s ID Card ([src.assignment])" /obj/item/weapon/card/id/proc/set_id_photo(var/mob/M) - var/icon/charicon = cached_character_icon(M) - front = icon(charicon,dir = SOUTH) - side = icon(charicon,dir = WEST) + COMPILE_OVERLAYS(M) + SSoverlays.queue -= M + var/icon/F = getFlatIcon(M, defdir = SOUTH, no_anim = TRUE) + front = "'data:image/png;base64,[icon2base64(F)]'" /mob/proc/set_id_info(var/obj/item/weapon/card/id/id_card) id_card.age = 0 @@ -75,19 +71,19 @@ ..() id_card.age = age -/obj/item/weapon/card/id/proc/dat() - var/dat = ("" - dat += "
") - dat += text("Name: []
", registered_name) - dat += text("Sex: []
\n", sex) - dat += text("Age: []
\n", age) - dat += text("Rank: []
\n", assignment) - dat += text("Fingerprint: []
\n", fingerprint_hash) - dat += text("Blood Type: []
\n", blood_type) - dat += text("DNA Hash: []

\n", dna_hash) - if(front && side) - dat +="
Photo:
" - return dat +/obj/item/weapon/card/id/tgui_data(mob/user) + var/list/data = list() + + data["registered_name"] = registered_name + data["sex"] = sex + data["age"] = age + data["assignment"] = assignment + data["fingerprint_hash"] = fingerprint_hash + data["blood_type"] = blood_type + data["dna_hash"] = dna_hash + data["photo_front"] = front + + return data /obj/item/weapon/card/id/attack_self(mob/user as mob) user.visible_message("\The [user] shows you: [bicon(src)] [src.name]. The assignment on the card: [src.assignment]",\ diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 25c08c725a..f267ac3654 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -1,5 +1,5 @@ #define TANK_MAX_RELEASE_PRESSURE (3*ONE_ATMOSPHERE) -#define TANK_DEFAULT_RELEASE_PRESSURE 24 +#define TANK_DEFAULT_RELEASE_PRESSURE 21 #define TANK_IDEAL_PRESSURE 1015 //Arbitrary. var/list/global/tank_gauge_cache = list() @@ -217,90 +217,73 @@ var/list/global/tank_gauge_cache = list() add_fingerprint(user) if (!(src.air_contents)) return - ui_interact(user) + tgui_interact(user) // There's GOT to be a better way to do this if (src.proxyassembly.assembly) src.proxyassembly.assembly.attack_self(user) -/obj/item/weapon/tank/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/mob/living/carbon/location = null +/obj/item/weapon/tank/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Tank", name) + ui.open() - if(istype(loc, /obj/item/weapon/rig)) // check for tanks in rigs - if(istype(loc.loc, /mob/living/carbon)) - location = loc.loc - else if(istype(loc, /mob/living/carbon)) - location = loc - - var/using_internal - if(istype(location)) - if(location.internal==src) - using_internal = 1 - - // this is the data which will be sent to the ui - var/data[0] +/obj/item/weapon/tank/tgui_data(mob/user) + var/list/data = list() data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) data["releasePressure"] = round(distribute_pressure ? distribute_pressure : 0) data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE) + data["minReleasePressure"] = 0 data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE) - data["valveOpen"] = using_internal ? 1 : 0 - data["maskConnected"] = 0 - if(istype(location)) - var/mask_check = 0 + var/mob/living/carbon/C = user + if(!istype(C)) + C = loc.loc + if(!istype(C)) + return data - if(location.internal == src) // if tank is current internal - mask_check = 1 - else if(src in location) // or if tank is in the mobs possession - if(!location.internal) // and they do not have any active internals - mask_check = 1 - else if(istype(src.loc, /obj/item/weapon/rig) && src.loc in location) // or the rig is in the mobs possession - if(!location.internal) // and they do not have any active internals - mask_check = 1 + if(C.internal == src) + data["connected"] = TRUE + else + data["connected"] = FALSE - if(mask_check) - if(location.wear_mask && (location.wear_mask.item_flags & AIRTIGHT)) - data["maskConnected"] = 1 - else if(istype(location, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = location - if(H.head && (H.head.item_flags & AIRTIGHT)) - data["maskConnected"] = 1 + data["maskConnected"] = FALSE + if(C.wear_mask && (C.wear_mask.item_flags & AIRTIGHT)) + data["maskConnected"] = TRUE + else if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(H.head && (H.head.item_flags & AIRTIGHT)) + data["maskConnected"] = TRUE - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "tanks.tmpl", "Tank", 500, 300) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + return data -/obj/item/weapon/tank/Topic(href, href_list) - ..() - if (usr.stat|| usr.restrained()) - return 0 - if (src.loc != usr) - return 0 +/obj/item/weapon/tank/tgui_act(action, params) + if(..()) + return TRUE + switch(action) + if("pressure") + var/pressure = params["pressure"] + if(pressure == "reset") + pressure = TANK_DEFAULT_RELEASE_PRESSURE + . = TRUE + else if(pressure == "min") + pressure = 0 + . = TRUE + else if(pressure == "max") + pressure = TANK_MAX_RELEASE_PRESSURE + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + distribute_pressure = clamp(round(pressure), 0, TANK_MAX_RELEASE_PRESSURE) + if("toggle") + toggle_valve(usr) + . = TRUE - if (href_list["dist_p"]) - if (href_list["dist_p"] == "reset") - src.distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE - else if (href_list["dist_p"] == "max") - src.distribute_pressure = TANK_MAX_RELEASE_PRESSURE - else - var/cp = text2num(href_list["dist_p"]) - src.distribute_pressure += cp - src.distribute_pressure = min(max(round(src.distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE) - if (href_list["stat"]) - toggle_valve(usr) - - src.add_fingerprint(usr) - return 1 + add_fingerprint(usr) /obj/item/weapon/tank/proc/toggle_valve(var/mob/user) if(istype(loc,/mob/living/carbon)) diff --git a/code/game/objects/items/weapons/towels.dm b/code/game/objects/items/weapons/towels.dm index b9566c399b..232a321202 100644 --- a/code/game/objects/items/weapons/towels.dm +++ b/code/game/objects/items/weapons/towels.dm @@ -10,6 +10,16 @@ desc = "A soft cotton towel." drop_sound = 'sound/items/drop/clothing.ogg' +/obj/item/weapon/towel/equipped(var/M, var/slot) + ..() + switch(slot) + if(slot_head) + sprite_sheets = list(SPECIES_TESHARI = 'icons/mob/species/seromi/head.dmi') + if(slot_wear_suit) + sprite_sheets = list(SPECIES_TESHARI = 'icons/mob/species/seromi/suit.dmi') + if(slot_belt) + sprite_sheets = list(SPECIES_TESHARI = 'icons/mob/species/seromi/belt.dmi') + /obj/item/weapon/towel/attack_self(mob/living/user as mob) user.visible_message(text("[] uses [] to towel themselves off.", user, src)) playsound(src, 'sound/weapons/towelwipe.ogg', 25, 1) diff --git a/code/game/objects/structures/ghost_pods/human.dm b/code/game/objects/structures/ghost_pods/human.dm index 2eda9b6c37..246c4b3e65 100644 --- a/code/game/objects/structures/ghost_pods/human.dm +++ b/code/game/objects/structures/ghost_pods/human.dm @@ -121,7 +121,7 @@ H.adjustBruteLoss(rand(1,20)) if(allow_appearance_change) - H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1) + H.change_appearance(APPEARANCE_ALL, H, check_species_whitelist = 1) visible_message("\The [src] [pick("gurgles", "seizes", "clangs")] before releasing \the [H]!") @@ -241,6 +241,6 @@ H.adjustBruteLoss(rand(1,20)) if(allow_appearance_change) - H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1) + H.change_appearance(APPEARANCE_ALL, H, check_species_whitelist = 1) visible_message("\The [src] [pick("gurgles", "seizes", "clangs")] before releasing \the [H]!") diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 4705b39276..1473c8fe90 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -7,10 +7,11 @@ density = 0 anchored = 1 var/shattered = 0 - var/list/ui_users = list() var/glass = 1 + var/datum/tgui_module/appearance_changer/mirror/M /obj/structure/mirror/New(var/loc, var/dir, var/building = 0, mob/user as mob) + M = new(src, null) if(building) glass = 0 icon_state = "mirror_frame" @@ -18,17 +19,16 @@ pixel_y = (dir & 3)? (dir == 1 ? -30 : 30) : 0 return +/obj/structure/mirror/Destroy() + QDEL_NULL(M) + . = ..() + /obj/structure/mirror/attack_hand(mob/user as mob) if(!glass) return if(shattered) return if(ishuman(user)) - var/datum/nano_module/appearance_changer/AC = ui_users[user] - if(!AC) - AC = new(src, user) - AC.name = "SalonPro Nano-Mirror™" - ui_users[user] = AC - AC.ui_interact(user) + M.tgui_interact(user) /obj/structure/mirror/proc/shatter() if(!glass) return diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index e994e1b760..c75186f923 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -1,3 +1,5 @@ +#define TANK_DISPENSER_CAPACITY 10 + /obj/structure/dispenser name = "tank storage unit" desc = "A simple yet bulky storage device for gas tanks. Has room for up to ten oxygen tanks, and ten phoron tanks." @@ -6,10 +8,8 @@ density = 1 anchored = 1.0 w_class = ITEMSIZE_HUGE - var/oxygentanks = 10 - var/phorontanks = 10 - var/list/oxytanks = list() //sorry for the similar var names - var/list/platanks = list() + var/oxygentanks = TANK_DISPENSER_CAPACITY + var/phorontanks = TANK_DISPENSER_CAPACITY /obj/structure/dispenser/oxygen @@ -19,10 +19,14 @@ oxygentanks = 0 -/obj/structure/dispenser/New() +/obj/structure/dispenser/Initialize() + . = ..() + for(var/i in 1 to oxygentanks) + new /obj/item/weapon/tank/oxygen(src) + for(var/i in 1 to phorontanks) + new /obj/item/weapon/tank/phoron(src) update_icon() - /obj/structure/dispenser/update_icon() overlays.Cut() switch(oxygentanks) @@ -32,49 +36,44 @@ if(1 to 4) overlays += "phoron-[phorontanks]" if(5 to INFINITY) overlays += "phoron-5" -/obj/structure/dispenser/attack_ai(mob/user as mob) +/obj/structure/dispenser/attack_ai(mob/user) + // This looks silly, but robots also call attack_ai, and they're allowed physical state stuff. if(user.Adjacent(src)) return attack_hand(user) ..() -/obj/structure/dispenser/attack_hand(mob/user as mob) - user.set_machine(src) - var/dat = "[src]

" - dat += "Oxygen tanks: [oxygentanks] - [oxygentanks ? "Dispense" : "empty"]
" - dat += "Phoron tanks: [phorontanks] - [phorontanks ? "Dispense" : "empty"]" - user << browse(dat, "window=dispenser") - onclose(user, "dispenser") - return +/obj/structure/dispenser/attack_hand(mob/user) + tgui_interact(user) +/obj/structure/dispenser/tgui_state(mob/user) + return GLOB.tgui_physical_state -/obj/structure/dispenser/attackby(obj/item/I as obj, mob/user as mob) +/obj/structure/dispenser/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TankDispenser", name) + ui.open() + +/obj/structure/dispenser/tgui_data(mob/user) + var/list/data = list() + data["oxygen"] = oxygentanks + data["plasma"] = phorontanks + + return data + +/obj/structure/dispenser/attackby(obj/item/I, mob/user) + var/full if(istype(I, /obj/item/weapon/tank/oxygen) || istype(I, /obj/item/weapon/tank/air) || istype(I, /obj/item/weapon/tank/anesthetic)) - if(oxygentanks < 10) - user.drop_item() - I.loc = src - oxytanks.Add(I) + if(oxygentanks < TANK_DISPENSER_CAPACITY) oxygentanks++ - to_chat(user, "You put [I] in [src].") - if(oxygentanks < 5) - update_icon() else - to_chat(user, "[src] is full.") - updateUsrDialog() - return - if(istype(I, /obj/item/weapon/tank/phoron)) - if(phorontanks < 10) - user.drop_item() - I.loc = src - platanks.Add(I) + full = TRUE + else if(istype(I, /obj/item/weapon/tank/phoron)) + if(phorontanks < TANK_DISPENSER_CAPACITY) phorontanks++ - to_chat(user, "You put [I] in [src].") - if(oxygentanks < 6) - update_icon() else - to_chat(user, "[src] is full.") - updateUsrDialog() - return - if(I.is_wrench()) + full = TRUE + else if(I.is_wrench()) if(anchored) to_chat(user, "You lean down and unwrench [src].") anchored = 0 @@ -82,39 +81,42 @@ to_chat(user, "You wrench [src] into place.") anchored = 1 return - -/obj/structure/dispenser/Topic(href, href_list) - if(usr.stat || usr.restrained()) + else if(user.a_intent != I_HURT) + to_chat(user, "[I] does not fit into [src].") return - if(Adjacent(usr)) - usr.set_machine(src) - if(href_list["oxygen"]) - if(oxygentanks > 0) - var/obj/item/weapon/tank/oxygen/O - if(oxytanks.len == oxygentanks) - O = oxytanks[1] - oxytanks.Remove(O) - else - O = new /obj/item/weapon/tank/oxygen(loc) - O.loc = loc - to_chat(usr, "You take [O] out of [src].") - oxygentanks-- - update_icon() - if(href_list["phoron"]) - if(phorontanks > 0) - var/obj/item/weapon/tank/phoron/P - if(platanks.len == phorontanks) - P = platanks[1] - platanks.Remove(P) - else - P = new /obj/item/weapon/tank/phoron(loc) - P.loc = loc - to_chat(usr, "You take [P] out of [src].") - phorontanks-- - update_icon() - add_fingerprint(usr) - updateUsrDialog() else - usr << browse(null, "window=dispenser") + return ..() + + if(full) + to_chat(user, "[src] can't hold any more of [I].") return - return + + if(!user.unEquip(I, target = src)) + return + to_chat(user, "You put [I] in [src].") + update_icon() + + +/obj/structure/dispenser/tgui_act(action, params) + if(..()) + return + switch(action) + if("plasma") + var/obj/item/weapon/tank/phoron/tank = locate() in src + if(tank && Adjacent(usr)) + usr.put_in_hands(tank) + phorontanks-- + . = TRUE + playsound(src, 'sound/machines/vending/vending_drop.ogg', 100, 1, 1) + if("oxygen") + var/obj/item/weapon/tank/tank = null + for(var/obj/item/weapon/tank/T in src) + if(istype(T, /obj/item/weapon/tank/oxygen) || istype(T, /obj/item/weapon/tank/air) || istype(T, /obj/item/weapon/tank/anesthetic)) + tank = T + break + if(tank && Adjacent(usr)) + usr.put_in_hands(tank) + oxygentanks-- + . = TRUE + playsound(src, 'sound/machines/vending/vending_drop.ogg', 100, 1, 1) + update_icon() \ No newline at end of file diff --git a/code/modules/admin/verbs/change_appearance.dm b/code/modules/admin/verbs/change_appearance.dm index e547d03f84..2f7166a2c0 100644 --- a/code/modules/admin/verbs/change_appearance.dm +++ b/code/modules/admin/verbs/change_appearance.dm @@ -9,7 +9,7 @@ if(!H) return log_and_message_admins("is altering the appearance of [H].") - H.change_appearance(APPEARANCE_ALL, usr, usr, check_species_whitelist = 0, state = admin_state) + H.change_appearance(APPEARANCE_ALL, usr, check_species_whitelist = 0, state = GLOB.tgui_admin_state) feedback_add_details("admin_verb","CHAA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/change_human_appearance_self() @@ -29,10 +29,10 @@ switch(alert("Do you wish for [H] to be allowed to select non-whitelisted races?","Alter Mob Appearance","Yes","No","Cancel")) if("Yes") log_and_message_admins("has allowed [H] to change [T.his] appearance, without whitelisting of races.") - H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 0) + H.change_appearance(APPEARANCE_ALL, H, check_species_whitelist = 0) if("No") log_and_message_admins("has allowed [H] to change [T.his] appearance, with whitelisting of races.") - H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1) + H.change_appearance(APPEARANCE_ALL, H, check_species_whitelist = 1) feedback_add_details("admin_verb","CMAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/editappear() diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index ffc0f97738..cf32d9ad4d 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -31,58 +31,53 @@ if(holder) holder.update_icon() -/obj/item/device/assembly/signaler/interact(var/mob/user) - var/t1 = "-------" - var/dat = {" - +/obj/item/device/assembly/signaler/interact(mob/user) + if(..()) + return TRUE + tgui_interact(user) -Send Signal
-Frequency/Code for signaler:
-Frequency: -- -- -[format_frequency(src.frequency)] -+ -+
+/obj/item/device/assembly/signaler/tgui_state(mob/user) + return GLOB.tgui_deep_inventory_state -Code: -- -- -[src.code] -+ -+
-[t1] -
"} - user << browse(dat, "window=radio") - onclose(user, "radio") +/obj/item/device/assembly/signaler/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Signaler", name) + ui.open() -/obj/item/device/assembly/signaler/Topic(href, href_list, state = deep_inventory_state) +/obj/item/device/assembly/signaler/tgui_data(mob/user) + var/list/data = list() + data["frequency"] = frequency + data["code"] = code + data["minFrequency"] = RADIO_LOW_FREQ + data["maxFrequency"] = RADIO_HIGH_FREQ + return data + +/obj/item/device/assembly/signaler/tgui_act(action, params) if(..()) return TRUE - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=radio") - onclose(usr, "radio") - return + switch(action) + if("signal") + INVOKE_ASYNC(src, .proc/signal) + . = TRUE + if("freq") + frequency = unformat_frequency(params["freq"]) + frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + set_frequency(frequency) + . = TRUE + if("code") + code = text2num(params["code"]) + code = clamp(round(code), 1, 100) + . = TRUE + if("reset") + if(params["reset"] == "freq") + set_frequency(initial(frequency)) + else + code = initial(code) + . = TRUE - if (href_list["freq"]) - var/new_frequency = (frequency + text2num(href_list["freq"])) - if(new_frequency < RADIO_LOW_FREQ || new_frequency > RADIO_HIGH_FREQ) - new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) - set_frequency(new_frequency) - - if(href_list["code"]) - src.code += text2num(href_list["code"]) - src.code = round(src.code) - src.code = min(100, src.code) - src.code = max(1, src.code) - - if(href_list["send"]) - spawn( 0 ) - signal() - - if(usr) - attack_self(usr) + update_icon() /obj/item/device/assembly/signaler/attackby(var/obj/item/weapon/W, mob/user, params) if(issignaler(W)) diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories.dm b/code/modules/client/preference_setup/loadout/loadout_accessories.dm index 01787a5931..e3abb37cd5 100644 --- a/code/modules/client/preference_setup/loadout/loadout_accessories.dm +++ b/code/modules/client/preference_setup/loadout/loadout_accessories.dm @@ -115,6 +115,15 @@ scarfs[initial(scarf_type.name)] = scarf_type gear_tweaks += new/datum/gear_tweak/path(sortAssoc(scarfs)) +/datum/gear/accessory/scarfcolor + display_name = "scarf (recolorable)" + path = /obj/item/clothing/accessory/scarf/white + cost = 1 + +/datum/gear/accessory/scarfcolor/New() + ..() + gear_tweaks = list(gear_tweak_free_color_choice) + /datum/gear/accessory/jacket display_name = "suit jacket selection" path = /obj/item/clothing/accessory/jacket diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm index 3ae9f2bf59..687435a7cf 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -77,7 +77,7 @@ /datum/gear/suit/mil display_name = "military jacket selection" path = /obj/item/clothing/suit/storage/miljacket - + /datum/gear/suit/mil/New() ..() var/list/mil_jackets = list() diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno.dm b/code/modules/client/preference_setup/loadout/loadout_xeno.dm index a2c2322286..a7669a837f 100644 --- a/code/modules/client/preference_setup/loadout/loadout_xeno.dm +++ b/code/modules/client/preference_setup/loadout/loadout_xeno.dm @@ -411,5 +411,15 @@ sort_category = "Xenowear" /datum/gear/suit/teshcoatwhite/New() + ..() + gear_tweaks = list(gear_tweak_free_color_choice) + +/datum/gear/accessory/teshneckscarf + display_name = "neckscarf, recolorable (Teshari)" + path = /obj/item/clothing/accessory/scarf/teshari/neckscarf + whitelisted = SPECIES_TESHARI + sort_category = "Xenowear" + +/datum/gear/accessory/teshneckscarf/New() ..() gear_tweaks = list(gear_tweak_free_color_choice) \ No newline at end of file diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 9032771739..f84d5d4ce7 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -339,6 +339,8 @@ datum/preferences else if(href_list["resetslot"]) if("No" == alert("This will reset the current slot. Continue?", "Reset current slot?", "No", "Yes")) return 0 + if("No" == alert("Are you completely sure that you want to reset this character slot?", "Reset current slot?", "No", "Yes")) + return 0 load_character(SAVE_RESET) sanitize_preferences() else if(href_list["copy"]) diff --git a/code/modules/clothing/glasses/hud_vr.dm b/code/modules/clothing/glasses/hud_vr.dm index ce49c88949..09e2af254d 100644 --- a/code/modules/clothing/glasses/hud_vr.dm +++ b/code/modules/clothing/glasses/hud_vr.dm @@ -100,12 +100,12 @@ mode = "sec" flash_protection = FLASH_PROTECTION_MAJOR action_button_name = "AR Console (Security Alerts)" - arscreen_path = /datum/nano_module/alarm_monitor/security + tgarscreen_path = /datum/tgui_module/alarm_monitor/security/glasses enables_planes = list(VIS_CH_ID,VIS_CH_HEALTH_VR,VIS_CH_WANTED,VIS_AUGMENTED) ar_interact(var/mob/living/carbon/human/user) - if(arscreen) - arscreen.ui_interact(user,"main",null,1,glasses_state) + if(tgarscreen) + tgarscreen.tgui_interact(user) return 1 /obj/item/clothing/glasses/omnihud/eng @@ -115,11 +115,11 @@ mode = "eng" flash_protection = FLASH_PROTECTION_MAJOR action_button_name = "AR Console (Station Alerts)" - arscreen_path = /datum/nano_module/alarm_monitor/engineering + tgarscreen_path = /datum/tgui_module/alarm_monitor/engineering/glasses ar_interact(var/mob/living/carbon/human/user) - if(arscreen) - arscreen.ui_interact(user,"main",null,1,glasses_state) + if(tgarscreen) + tgarscreen.tgui_interact(user) return 1 /obj/item/clothing/glasses/omnihud/rnd diff --git a/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm b/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm index 6dc5fc4f01..e6848a66d0 100644 --- a/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm +++ b/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm @@ -15,7 +15,7 @@ to_chat(usr, "Your module is not installed in a hardsuit.") return - module.holder.ui_interact(usr, nano_state = contained_state) + module.holder.tgui_interact(usr, custom_state = GLOB.tgui_contained_state) /obj/item/rig_module/ai_container @@ -134,7 +134,7 @@ if(!target) if(ai_card) if(istype(ai_card,/obj/item/device/aicard)) - ai_card.ui_interact(H, state = deep_inventory_state) + ai_card.tgui_interact(H, custom_state = deep_inventory_state) else eject_ai(H) update_verb_holder() diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index 1afd78dee0..140bf6ecc9 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -28,8 +28,8 @@ var/suit_state //The string used for the suit's icon_state. - var/interface_path = "hardsuit.tmpl" - var/ai_interface_path = "hardsuit.tmpl" + var/interface_path = "RIGSuit" + var/ai_interface_path = "RIGSuit" var/interface_title = "Hardsuit Controller" var/wearer_move_delay //Used for AI moving. var/ai_controlled_move_delay = 10 @@ -284,6 +284,7 @@ if(!seal_target && !suit_is_deployed()) M.visible_message("[M]'s suit flashes an error light.","Your suit flashes an error light. It can't function properly without being fully deployed.") + playsound(src, 'sound/machines/rig/rigerror.ogg', 20, FALSE) failed_to_seal = 1 if(!failed_to_seal) @@ -293,6 +294,7 @@ if(seal_delay && !do_after(M,seal_delay)) if(M) to_chat(M, "You must remain still while the suit is adjusting the components.") + playsound(src, 'sound/machines/rig/rigerror.ogg', 20, FALSE) failed_to_seal = 1 if(!M) failed_to_seal = 1 @@ -340,6 +342,7 @@ piece.armor["bio"] = 100 else piece.armor["bio"] = src.armor["bio"] + playsound(src, "[!seal_target ? 'sound/machines/boltsdown.ogg' : 'sound/machines/boltsup.ogg']", 10, FALSE) else failed_to_seal = 1 @@ -371,6 +374,7 @@ else minihud = new (M.hud_used, src) to_chat(M, "Your entire suit [canremove ? "loosens as the components relax" : "tightens around you as the components lock into place"].") + playsound(src, 'sound/machines/rig/rigstarted.ogg', 10, FALSE) M.client.screen -= booting_L qdel(booting_L) booting_R.icon_state = "boot_done" @@ -493,7 +497,7 @@ wearer.wearing_rig = null wearer = null return PROCESS_KILL - + // Run through cooling coolingProcess() @@ -508,6 +512,7 @@ to_chat(wearer, "Your suit beeps stridently, and suddenly goes dead.") else to_chat(wearer, "Your suit beeps stridently, and suddenly you're wearing a leaden mass of metal and plastic composites instead of a powered suit.") + playsound(src, 'sound/machines/rig/rigdown.ogg', 60, FALSE) if(offline_vision_restriction == 1) to_chat(wearer, "The suit optics flicker and die, leaving you with restricted vision.") else if(offline_vision_restriction == 2) @@ -565,6 +570,7 @@ if(fail_msg) to_chat(user, fail_msg) + playsound(src, 'sound/machines/rig/rigerror.ogg', 20, FALSE) return 0 // This is largely for cancelling stealth and whatever. @@ -576,81 +582,6 @@ cell.use(cost*10) return 1 -/obj/item/weapon/rig/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/nano_state = inventory_state) - if(!user) - return - - var/list/data = list() - - if(selected_module) - data["primarysystem"] = "[selected_module.interface_name]" - - if(src.loc != user) - data["ai"] = 1 - - data["seals"] = "[src.canremove]" - data["sealing"] = "[src.sealing]" - data["helmet"] = (helmet ? "[helmet.name]" : "None.") - data["gauntlets"] = (gloves ? "[gloves.name]" : "None.") - data["boots"] = (boots ? "[boots.name]" : "None.") - data["chest"] = (chest ? "[chest.name]" : "None.") - - data["charge"] = cell ? round(cell.charge,1) : 0 - data["maxcharge"] = cell ? cell.maxcharge : 0 - data["chargestatus"] = cell ? FLOOR((cell.charge/cell.maxcharge)*50, 1) : 0 - - data["emagged"] = subverted - data["coverlock"] = locked - data["interfacelock"] = interface_locked - data["aicontrol"] = control_overridden - data["aioverride"] = ai_override_enabled - data["securitycheck"] = security_check_enabled - data["malf"] = malfunction_delay - - - var/list/module_list = list() - var/i = 1 - for(var/obj/item/rig_module/module in installed_modules) - var/list/module_data = list( - "index" = i, - "name" = "[module.interface_name]", - "desc" = "[module.interface_desc]", - "can_use" = "[module.usable]", - "can_select" = "[module.selectable]", - "can_toggle" = "[module.toggleable]", - "is_active" = "[module.active]", - "engagecost" = module.use_power_cost*10, - "activecost" = module.active_power_cost*10, - "passivecost" = module.passive_power_cost*10, - "engagestring" = module.engage_string, - "activatestring" = module.activate_string, - "deactivatestring" = module.deactivate_string, - "damage" = module.damage - ) - - if(module.charges && module.charges.len) - - module_data["charges"] = list() - var/datum/rig_charge/selected = module.charges[module.charge_selected] - module_data["chargetype"] = selected ? "[selected.display_name]" : "none" - - for(var/chargetype in module.charges) - var/datum/rig_charge/charge = module.charges[chargetype] - module_data["charges"] += list(list("caption" = "[chargetype] ([charge.charges])", "index" = "[chargetype]")) - - module_list += list(module_data) - i++ - - if(module_list.len) - data["modules"] = module_list - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, ((src.loc != user) ? ai_interface_path : interface_path), interface_title, 480, 550, state = nano_state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - /obj/item/weapon/rig/update_icon(var/update_mob_icon) //TODO: Maybe consider a cache for this (use mob_icon as blank canvas, use suit icon overlay). @@ -698,44 +629,6 @@ return 1 -//TODO: Fix Topic vulnerabilities for malfunction and AI override. -/obj/item/weapon/rig/Topic(href,href_list) - if(!check_suit_access(usr)) - return 0 - - if(href_list["toggle_piece"]) - if(ishuman(usr) && (usr.stat || usr.stunned || usr.lying)) - return 0 - toggle_piece(href_list["toggle_piece"], usr) - else if(href_list["toggle_seals"]) - toggle_seals(usr) - else if(href_list["interact_module"]) - - var/module_index = text2num(href_list["interact_module"]) - - if(module_index > 0 && module_index <= installed_modules.len) - var/obj/item/rig_module/module = installed_modules[module_index] - switch(href_list["module_mode"]) - if("activate") - module.activate() - if("deactivate") - module.deactivate() - if("engage") - module.engage() - if("select") - selected_module = module - if("select_charge_type") - module.charge_selected = href_list["charge_type"] - else if(href_list["toggle_ai_control"]) - ai_override_enabled = !ai_override_enabled - notify_ai("Synthetic suit control has been [ai_override_enabled ? "enabled" : "disabled"].") - else if(href_list["toggle_suit_lock"]) - locked = !locked - - usr.set_machine(src) - src.add_fingerprint(usr) - return 0 - /obj/item/weapon/rig/proc/notify_ai(var/message) for(var/obj/item/rig_module/ai_container/module in installed_modules) if(module.integrated_ai && module.integrated_ai.client && !module.integrated_ai.stat) @@ -814,6 +707,7 @@ if(istype(holder)) if(use_obj && check_slot == use_obj) to_chat(H, "Your [use_obj.name] [use_obj.gender == PLURAL ? "retract" : "retracts"] swiftly.") + playsound(src, 'sound/machines/boltsup.ogg', 10, FALSE) use_obj.canremove = 1 holder.drop_from_inventory(use_obj) use_obj.forceMove(get_turf(src)) @@ -832,6 +726,7 @@ return else to_chat(H, "Your [use_obj.name] [use_obj.gender == PLURAL ? "deploy" : "deploys"] swiftly.") + playsound(src, 'sound/machines/boltsdown.ogg', 10, FALSE) if(piece == "helmet" && helmet) helmet.update_light(H) diff --git a/code/modules/clothing/spacesuits/rig/rig_tgui.dm b/code/modules/clothing/spacesuits/rig/rig_tgui.dm new file mode 100644 index 0000000000..5fc1e17380 --- /dev/null +++ b/code/modules/clothing/spacesuits/rig/rig_tgui.dm @@ -0,0 +1,164 @@ +/* + * This defines the global UI for RIGSuits. + * It has all of the relevant TGUI procs, but it's entry point is in rig_verbs.dm + * as part of rig/proc/hardsuit_interface(). + */ + +/* + * tgui_interact() is the proc that opens the UI. It doesn't really do anything else, unlike NanoV1. + * We add an extra argument, custom_state, for the things that want a custom state for their UI. + */ +/obj/item/weapon/rig/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/tgui_state/custom_state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, (loc != usr ? ai_interface_path : interface_path), interface_title) + ui.open() + if(custom_state) + ui.set_state(custom_state) + +/* + * tgui_state() gives the UI the state to use by default. + */ +/obj/item/weapon/rig/tgui_state() + return GLOB.tgui_inventory_state + +/* + * tgui_status() is middlewere for objects to add little exceptions or special cases to the state they use. + * In this case, we're using it in order to make the UI refuse to let the user press any buttons if they're + * not authorized to do so. + * This saves us two lines of code in tgui_act(). + */ +/obj/item/weapon/rig/tgui_status(mob/user, datum/tgui_state/state) + . = ..() + if(!check_suit_access(user)) + // Forces the UI to never go interactive, + // but doesn't interfere with state saying to close. + . = min(., STATUS_UPDATE) + +/* + * tgui_data() is the heavy lifter, it gives the UI it's relevant datastructure every SStgui tick. + */ +/obj/item/weapon/rig/tgui_data(mob/user) + var/list/data = list() + + if(selected_module) + data["primarysystem"] = "[selected_module.interface_name]" + else + data["primarysystem"] = null + + if(loc != user) + data["ai"] = TRUE + else + data["ai"] = FALSE + + data["sealed"] = !canremove + data["sealing"] = sealing + data["helmet"] = (helmet ? "[helmet.name]" : "None.") + data["gauntlets"] = (gloves ? "[gloves.name]" : "None.") + data["boots"] = (boots ? "[boots.name]" : "None.") + data["chest"] = (chest ? "[chest.name]" : "None.") + + data["helmetDeployed"] = (helmet && helmet.loc == loc) + data["gauntletsDeployed"] = (gloves && gloves.loc == loc) + data["bootsDeployed"] = (boots && boots.loc == loc) + data["chestDeployed"] = (chest && chest.loc == loc) + + data["charge"] = cell ? round(cell.charge,1) : 0 + data["maxcharge"] = cell ? cell.maxcharge : 0 + data["chargestatus"] = cell ? FLOOR((cell.charge/cell.maxcharge)*50, 1) : 0 + + data["emagged"] = subverted + data["coverlock"] = locked + data["interfacelock"] = interface_locked + data["aicontrol"] = control_overridden + data["aioverride"] = ai_override_enabled + data["securitycheck"] = security_check_enabled + data["malf"] = malfunction_delay + + var/list/module_list = list() + if(!canremove && !sealing) + var/i = 1 + for(var/obj/item/rig_module/module in installed_modules) + var/list/module_data = list( + "index" = i, + "name" = "[module.interface_name]", + "desc" = "[module.interface_desc]", + "can_use" = module.usable, + "can_select" = module.selectable, + "can_toggle" = module.toggleable, + "is_active" = module.active, + "engagecost" = module.use_power_cost*10, + "activecost" = module.active_power_cost*10, + "passivecost" = module.passive_power_cost*10, + "engagestring" = module.engage_string, + "activatestring" = module.activate_string, + "deactivatestring" = module.deactivate_string, + "damage" = module.damage + ) + + if(module.charges && module.charges.len) + module_data["charges"] = list() + var/datum/rig_charge/selected = module.charges[module.charge_selected] + module_data["chargetype"] = selected ? "[selected.display_name]" : "none" + + for(var/chargetype in module.charges) + var/datum/rig_charge/charge = module.charges[chargetype] + module_data["charges"] += list(list("caption" = "[chargetype] ([charge.charges])", "index" = "[chargetype]")) + + module_list += list(module_data) + i++ + + if(module_list.len) + data["modules"] = module_list + else + data["modules"] = list() + + return data + +/* + * tgui_act() is the TGUI equivelent of Topic(). It's responsible for all of the "actions" you can take in the UI. + */ +/obj/item/weapon/rig/tgui_act(action, params) + // This parent call is very important, as it's responsible for invoking tgui_status and checking our state's rules. + if(..()) + return TRUE + + add_fingerprint(usr) + + switch(action) + if("toggle_seals") + toggle_seals(usr) + . = TRUE + if("toggle_ai_control") + ai_override_enabled = !ai_override_enabled + notify_ai("Synthetic suit control has been [ai_override_enabled ? "enabled" : "disabled"].") + . = TRUE + if("toggle_suit_lock") + locked = !locked + . = TRUE + if("toggle_piece") + if(ishuman(usr) && (usr.stat || usr.stunned || usr.lying)) + return FALSE + toggle_piece(params["piece"], usr) + . = TRUE + if("interact_module") + var/module_index = text2num(params["module"]) + + if(module_index > 0 && module_index <= installed_modules.len) + var/obj/item/rig_module/module = installed_modules[module_index] + switch(params["module_mode"]) + if("select") + selected_module = module + . = TRUE + if("engage") + module.engage() + . = TRUE + if("toggle") + if(module.active) + module.deactivate() + else + module.activate() + . = TRUE + if("select_charge_type") + module.charge_selected = params["charge_type"] + . = TRUE \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/rig/rig_verbs.dm b/code/modules/clothing/spacesuits/rig/rig_verbs.dm index 9f832ec911..ea56adb1e6 100644 --- a/code/modules/clothing/spacesuits/rig/rig_verbs.dm +++ b/code/modules/clothing/spacesuits/rig/rig_verbs.dm @@ -7,7 +7,7 @@ set src = usr.contents if(wearer && (wearer.back == src || wearer.belt == src)) - ui_interact(usr) + tgui_interact(usr) /obj/item/weapon/rig/verb/toggle_vision() diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index 6aed5daf39..5591100ca6 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -4,16 +4,17 @@ icon = 'icons/obj/clothing/ties.dmi' icon_state = "bluetie" item_state_slots = list(slot_r_hand_str = "", slot_l_hand_str = "") + appearance_flags = RESET_COLOR // Stops has_suit's color from being multiplied onto the accessory slot_flags = SLOT_TIE w_class = ITEMSIZE_SMALL var/slot = ACCESSORY_SLOT_DECOR - var/obj/item/clothing/has_suit = null //the suit the tie may be attached to - var/image/inv_overlay = null //overlay used when attached to clothing. + var/obj/item/clothing/has_suit = null // The suit the tie may be attached to + var/image/inv_overlay = null // Overlay used when attached to clothing. var/image/mob_overlay = null var/overlay_state = null var/concealed_holster = 0 - var/mob/living/carbon/human/wearer = null //To check if the wearer changes, so species spritesheets change properly. - var/list/on_rolled = list() //used when jumpsuit sleevels are rolled ("rolled" entry) or it's rolled down ("down"). Set to "none" to hide in those states. + var/mob/living/carbon/human/wearer = null // To check if the wearer changes, so species spritesheets change properly. + var/list/on_rolled = list() // Used when jumpsuit sleevels are rolled ("rolled" entry) or it's rolled down ("down"). Set to "none" to hide in those states. sprite_sheets = list(SPECIES_TESHARI = 'icons/mob/species/seromi/ties.dmi') //Teshari can into webbing, too! /obj/item/clothing/accessory/Destroy() @@ -29,6 +30,9 @@ inv_overlay = image(icon = icon_override, icon_state = tmp_icon_state, dir = SOUTH) else inv_overlay = image(icon = INV_ACCESSORIES_DEF_ICON, icon_state = tmp_icon_state, dir = SOUTH) + + inv_overlay.color = src.color + inv_overlay.appearance_flags = appearance_flags // Stops has_suit's color from being multiplied onto the accessory return inv_overlay /obj/item/clothing/accessory/proc/get_mob_overlay() @@ -65,6 +69,7 @@ else mob_overlay.color = src.color + mob_overlay.appearance_flags = appearance_flags // Stops has_suit's color from being multiplied onto the accessory return mob_overlay //when user attached an accessory to S @@ -72,8 +77,8 @@ if(!istype(S)) return has_suit = S - loc = has_suit - has_suit.overlays += get_inv_overlay() + src.forceMove(S) + has_suit.add_overlay(get_inv_overlay()) if(user) to_chat(user, "You attach \the [src] to \the [has_suit].") @@ -82,7 +87,7 @@ /obj/item/clothing/accessory/proc/on_removed(var/mob/user) if(!has_suit) return - has_suit.overlays -= get_inv_overlay() + has_suit.cut_overlay(get_inv_overlay()) has_suit = null if(user) usr.put_in_hands(src) @@ -325,6 +330,12 @@ name = "striped blue scarf" icon_state = "stripedbluescarf" +/obj/item/clothing/accessory/scarf/teshari/neckscarf + name = "small neckscarf" + desc = "a neckscarf that is too small for a human's neck" + icon_state = "tesh_neckscarf" + species_restricted = list(SPECIES_TESHARI) + //bracelets /obj/item/clothing/accessory/bracelet diff --git a/code/modules/clothing/under/xenos/seromi.dm b/code/modules/clothing/under/xenos/seromi.dm index 0e43030ade..5126ab1460 100644 --- a/code/modules/clothing/under/xenos/seromi.dm +++ b/code/modules/clothing/under/xenos/seromi.dm @@ -45,6 +45,22 @@ name = "small formal uniform" icon_state = "seromi_captain_formal" +/obj/item/clothing/under/seromi/smock/blackutilitysmock + name = "black utility smock" + icon_state = "teshari_blackutility_com" + +/obj/item/clothing/under/seromi/smock/greydress + name = "small grey dress" + icon_state = "teshari_greydress" + +/obj/item/clothing/under/seromi/smock/blackutility + name = "Teshari utility uniform" + icon_state = "teshari_blackutility" + +/obj/item/clothing/under/seromi/smock/bluegreydress + name = "small blue and grey dress" + icon_state = "teshari_bluegreydress" + /obj/item/clothing/under/seromi/undercoat name = "Undercoat" desc = "A Teshari traditional garb, with a modern twist! Made of micro and nanofibres to make it light and billowy, perfect for going fast and stylishly!" @@ -179,6 +195,66 @@ icon_state = "tesh_uniform_brg" item_state = "tesh_uniform_brg" +/obj/item/clothing/under/seromi/undercoat/standard/blackredworksuit + name = "small black and red worksuit" + icon_state = "teshari_black_red_worksuit" + item_state = "teshari_black_red_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/blackpurpleworksuit + name = "small black and purple worksuit" + icon_state = "teshari_black_purple_worksuit" + item_state = "teshari_black_purple_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/blackpurpleworksuit + name = "small black and orange worksuit" + icon_state = "teshari_black_orange_worksuit" + item_state = "teshari_black_orange_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/blackblueworksuit + name = "small black and blue worksuit" + icon_state = "teshari_black_blue_worksuit" + item_state = "teshari_black_blue_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/blackgreenworksuit + name = "small black and greeen worksuit" + icon_state = "teshari_black_green_worksuit" + item_state = "teshari_black_green_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/whiteredworksuit + name = "small white and red worksuit" + icon_state = "teshari_white_red_worksuit" + item_state = "teshari_white_red_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/whitepurpleworksuit + name = "small white and purple worksuit" + icon_state = "teshari_white_purple_worksuit" + item_state = "teshari_white_purple_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/whiteorangeworksuit + name = "small white and orange worksuit" + icon_state = "teshari_white_orange_worksuit" + item_state = "teshari_white_orange_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/whiteblueworksuit + name = "small white and blue worksuit" + icon_state = "teshari_white_blue_worksuit" + item_state = "teshari_white_blue_worksuit" + desc = "A small worksuit designed for a Teshari" + +/obj/item/clothing/under/seromi/undercoat/standard/whitegreenworksuit + name = "small white and green worksuit" + icon_state = "teshari_white_green_worksuit" + item_state = "teshari_white_green_worksuit" + desc = "A small worksuit designed for a Teshari" + /obj/item/clothing/under/seromi/undercoat/jobs icon = 'icons/mob/species/seromi/deptjacket.dmi' icon_override = 'icons/mob/species/seromi/deptjacket.dmi' @@ -295,4 +371,4 @@ name = "internal affairs undercoat" desc = "A traditional Teshari garb made for the Internal Affairs Agent" icon_state = "tesh_uniform_iaa" - item_state = "tesh_uniform_iaa" + item_state = "tesh_uniform_iaa" \ No newline at end of file diff --git a/code/modules/food/kitchen/microwave.dm b/code/modules/food/kitchen/microwave.dm index 3e40412b1b..065d036920 100644 --- a/code/modules/food/kitchen/microwave.dm +++ b/code/modules/food/kitchen/microwave.dm @@ -100,7 +100,7 @@ src.icon_state = "mw" src.broken = 0 // Fix it! src.dirty = 0 // just to be sure - src.flags = OPENCONTAINER + src.flags = OPENCONTAINER | NOREACT else to_chat(user, "It's broken!") return 1 @@ -119,7 +119,7 @@ src.dirty = 0 // It's clean! src.broken = 0 // just to be sure src.icon_state = "mw" - src.flags = OPENCONTAINER + src.flags = OPENCONTAINER | NOREACT else //Otherwise bad luck!! to_chat(user, "It's dirty!") return 1 @@ -546,4 +546,4 @@ if(istype(container, /obj/machinery/microwave)) var/obj/machinery/microwave/M = container M.muck_finish() - . = ..() \ No newline at end of file + . = ..() diff --git a/code/modules/food/kitchen/smartfridge.dm b/code/modules/food/kitchen/smartfridge.dm index c798ed3875..7184b2f68c 100644 --- a/code/modules/food/kitchen/smartfridge.dm +++ b/code/modules/food/kitchen/smartfridge.dm @@ -243,7 +243,6 @@ user.visible_message("[user] [panel_open ? "opens" : "closes"] the maintenance panel of \the [src].", "You [panel_open ? "open" : "close"] the maintenance panel of \the [src].") playsound(src, O.usesound, 50, 1) update_icon() - SSnanoui.update_uis(src) return if(wrenchable && default_unfasten_wrench(user, O, 20)) @@ -263,7 +262,6 @@ stock(O) user.visible_message("[user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].") - else if(istype(O, /obj/item/weapon/storage/bag)) var/obj/item/weapon/storage/bag/P = O var/plants_loaded = 0 @@ -309,11 +307,11 @@ var/datum/stored_item/item = new/datum/stored_item(src, O.type, O.name) item.add_product(O) item_records.Add(item) - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/smartfridge/proc/vend(datum/stored_item/I) I.get_product(get_turf(src)) - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/smartfridge/attack_ai(mob/user as mob) attack_hand(user) @@ -322,66 +320,59 @@ if(stat & (NOPOWER|BROKEN)) return wires.Interact(user) - ui_interact(user) + tgui_interact(user) -/******************* -* SmartFridge Menu -********************/ +/obj/machinery/smartfridge/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SmartVend", name) + ui.set_autoupdate(FALSE) + ui.open() -/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/smartfridge/tgui_data(mob/user) + . = list() - var/data[0] - data["contents"] = null - data["electrified"] = seconds_electrified > 0 - data["shoot_inventory"] = shoot_inventory - data["locked"] = locked - data["secure"] = is_secure - - var/list/items[0] - for (var/i=1 to length(item_records)) + var/list/items = list() + for(var/i=1 to length(item_records)) var/datum/stored_item/I = item_records[i] var/count = I.get_amount() if(count > 0) - items.Add(list(list("display_name" = html_encode(capitalize(I.item_name)), "vend" = i, "quantity" = count))) + items.Add(list(list("name" = html_encode(capitalize(I.item_name)), "index" = i, "amount" = count))) - if(items.len > 0) - data["contents"] = items + .["contents"] = items + .["name"] = name + .["locked"] = locked + .["secure"] = is_secure - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "smartfridge.tmpl", src.name, 400, 500) - ui.set_initial_data(data) - ui.open() +/obj/machinery/smartfridge/tgui_act(action, params) + if(..()) + return TRUE -/obj/machinery/smartfridge/Topic(href, href_list) - if(..()) return 0 + add_fingerprint(usr) + switch(action) + if("Release") + var/amount = 0 + if(params["amount"]) + amount = params["amount"] + else + amount = input("How many items?", "How many items would you like to take out?", 1) as num|null + + if(QDELETED(src) || QDELETED(usr) || !usr.Adjacent(src)) + return FALSE + + var/index = text2num(params["index"]) + var/datum/stored_item/I = item_records[index] + var/count = I.get_amount() - var/mob/user = usr - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") + // Sanity check, there are probably ways to press the button when it shouldn't be possible. + if(count > 0) + if((count - amount) < 0) + amount = count + for(var/i = 1 to amount) + vend(I) - src.add_fingerprint(user) - - if(href_list["close"]) - user.unset_machine() - ui.close() - return 0 - - if(href_list["vend"]) - var/index = text2num(href_list["vend"]) - var/amount = text2num(href_list["amount"]) - var/datum/stored_item/I = item_records[index] - var/count = I.get_amount() - - // Sanity check, there are probably ways to press the button when it shouldn't be possible. - if(count > 0) - if((count - amount) < 0) - amount = count - for(var/i = 1 to amount) - vend(I) - - return 1 - return 0 + return TRUE + return FALSE /obj/machinery/smartfridge/proc/throw_item() var/obj/throw_item = null @@ -400,17 +391,18 @@ spawn(0) throw_item.throw_at(target,16,3,src) src.visible_message("[src] launches [throw_item.name] at [target.name]!") + SStgui.update_uis(src) return 1 /************************ * Secure SmartFridges *************************/ -/obj/machinery/smartfridge/secure/Topic(href, href_list) +/obj/machinery/smartfridge/secure/tgui_act(action, params) if(stat & (NOPOWER|BROKEN)) - return 0 + return TRUE if(usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf))) - if(!allowed(usr) && !emagged && locked != -1 && href_list["vend"]) + if(!allowed(usr) && !emagged && locked != -1 && action == "Release") to_chat(usr, "Access denied.") - return 0 + return TRUE return ..() diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index eae3c47335..b1424ae5b0 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -1,7 +1,12 @@ -/mob/living/carbon/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR, var/location = src, var/mob/user = src, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list(), var/datum/topic_state/state = default_state) - var/datum/nano_module/appearance_changer/AC = new(location, src, check_species_whitelist, species_whitelist, species_blacklist) +/mob/living/carbon/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR, + var/mob/user = src, + var/check_species_whitelist = 1, + var/list/species_whitelist = list(), + var/list/species_blacklist = list(), + var/datum/tgui_state/state = GLOB.tgui_self_state) + var/datum/tgui_module/appearance_changer/AC = new(src, src, check_species_whitelist, species_whitelist, species_blacklist) AC.flags = flags - AC.ui_interact(user, state = state) + AC.tgui_interact(user, custom_state = state) /mob/living/carbon/human/proc/change_species(var/new_species) if(!new_species) diff --git a/code/modules/mob/living/carbon/human/emote_vr.dm b/code/modules/mob/living/carbon/human/emote_vr.dm index 7dbce009ac..2be90ec8dc 100644 --- a/code/modules/mob/living/carbon/human/emote_vr.dm +++ b/code/modules/mob/living/carbon/human/emote_vr.dm @@ -172,7 +172,7 @@ message = "does a flip!" m_type = 1 if("vhelp") //Help for Virgo-specific emotes. - to_chat(src, "vwag, vflap, mlem, blep, awoo, awoo2, growl, nya, peep, chirp, hoot, weh, merp, myarp, bark, bork, mrow, mrowl, hypno, hiss, rattle, squeak, geck, baa, baa2, mar, wurble, snort, meow, moo, croak, nsay, nme, flip") + to_chat(src, "vwag, vflap, mlem, blep, awoo, awoo2, growl, nya, peep, chirp, hoot, weh, merp, myarp, bark, bork, mrow, mrowl, hypno, hiss, rattle, squeak, geck, baa, baa2, mar, wurble, snort, meow, moo, croak, gao, cackle, nsay, nme, flip") return TRUE if(message) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/code/modules/mob/living/silicon/robot/drone/drone_console.dm index c2e6ca48f5..94b8bb2e2c 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_console.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_console.dm @@ -14,111 +14,107 @@ /obj/machinery/computer/drone_control/attack_ai(var/mob/user as mob) return src.attack_hand(user) +/obj/machinery/computer/drone_control/tgui_status(mob/user) + if(!allowed(user)) + return STATUS_CLOSE + return ..() + /obj/machinery/computer/drone_control/attack_hand(var/mob/user as mob) if(..()) return - if(!allowed(user)) - to_chat(user, "Access denied.") - return + tgui_interact(user) - user.set_machine(src) - var/dat - dat += "Maintenance Units
" +/obj/machinery/computer/drone_control/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "DroneConsole", name) + ui.open() +/obj/machinery/computer/drone_control/tgui_data(mob/user) + var/list/data = list() + + data["drones"] = list() for(var/mob/living/silicon/robot/drone/D in mob_list) - if(D.z != src.z) + if(D.z != z) continue if(D.foreign_droid) continue + + data["drones"].Add(list(list( + "name" = D.real_name, + "active" = D.stat != 2, + "charge" = D.cell.charge, + "maxCharge" = D.cell.maxcharge, + "loc" = "[get_area(D)]", + "ref" = "\ref[D]", + ))) - dat += "
[D.real_name] ([D.stat == 2 ? "INACTIVE" : "ACTIVE"])" - dat += "
Cell charge: [D.cell.charge]/[D.cell.maxcharge]." - dat += "
Currently located in: [get_area(D)]." - dat += "
Resync | Shutdown
" + data["fabricator"] = dronefab + data["fabPower"] = dronefab?.produce_drones - dat += "

Request drone presence in area: [drone_call_area] (Send ping)" + data["areas"] = tagger_locations + data["selected_area"] = "[drone_call_area]" - dat += "

Drone fabricator: " - dat += "[dronefab ? "[(dronefab.produce_drones && !(dronefab.stat & NOPOWER)) ? "ACTIVE" : "INACTIVE"]" : "FABRICATOR NOT DETECTED. (search)"]" - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return + return data - -/obj/machinery/computer/drone_control/Topic(href, href_list) +/obj/machinery/computer/drone_control/tgui_act(action, params) if(..()) - return + return TRUE - if(!allowed(usr)) - to_chat(usr, "Access denied.") - return + switch(action) + if("set_dcall_area") + var/t_area = params["area"] + if(!t_area || !(t_area in tagger_locations)) + return - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) + drone_call_area = t_area + to_chat(usr, "You set the area selector to [drone_call_area].") - if (href_list["setarea"]) + if("ping") + to_chat(usr, "You issue a maintenance request for all active drones, highlighting [drone_call_area].") + for(var/mob/living/silicon/robot/drone/D in player_list) + if(D.stat == 0) + to_chat(D, "-- Maintenance drone presence requested in: [drone_call_area].") - //Probably should consider using another list, but this one will do. - var/t_area = input("Select the area to ping.", "Set Target Area", null) as null|anything in tagger_locations + if("resync") + var/mob/living/silicon/robot/drone/D = locate(params["ref"]) - if(!t_area) - return + if(D.stat != 2) + to_chat(usr, "You issue a law synchronization directive for the drone.") + D.law_resync() - drone_call_area = t_area - to_chat(usr, "You set the area selector to [drone_call_area].") + if("shutdown") + var/mob/living/silicon/robot/drone/D = locate(params["ref"]) - else if (href_list["ping"]) + if(D.stat != 2) + to_chat(usr, "You issue a kill command for the unfortunate drone.") + message_admins("[key_name_admin(usr)] issued kill order for drone [key_name_admin(D)] from control console.") + log_game("[key_name(usr)] issued kill order for [key_name(src)] from control console.") + D.shut_down() - to_chat(usr, "You issue a maintenance request for all active drones, highlighting [drone_call_area].") - for(var/mob/living/silicon/robot/drone/D in player_list) - if(D.stat == 0) - to_chat(D, "-- Maintenance drone presence requested in: [drone_call_area].") + if("search_fab") + if(dronefab) + return - else if (href_list["resync"]) + for(var/obj/machinery/drone_fabricator/fab in oview(3,src)) + if(fab.stat & NOPOWER) + continue - var/mob/living/silicon/robot/drone/D = locate(href_list["resync"]) + dronefab = fab + to_chat(usr, "Drone fabricator located.") + return - if(D.stat != 2) - to_chat(usr, "You issue a law synchronization directive for the drone.") - D.law_resync() - - else if (href_list["shutdown"]) - - var/mob/living/silicon/robot/drone/D = locate(href_list["shutdown"]) - - if(D.stat != 2) - to_chat(usr, "You issue a kill command for the unfortunate drone.") - message_admins("[key_name_admin(usr)] issued kill order for drone [key_name_admin(D)] from control console.") - log_game("[key_name(usr)] issued kill order for [key_name(src)] from control console.") - D.shut_down() - - else if (href_list["search_fab"]) - if(dronefab) - return - - for(var/obj/machinery/drone_fabricator/fab in oview(3,src)) - - if(fab.stat & NOPOWER) - continue - - dronefab = fab - to_chat(usr, "Drone fabricator located.") - return - - to_chat(usr, "Unable to locate drone fabricator.") - - else if (href_list["toggle_fab"]) - - if(!dronefab) - return - - if(get_dist(src,dronefab) > 3) - dronefab = null to_chat(usr, "Unable to locate drone fabricator.") - return - dronefab.produce_drones = !dronefab.produce_drones - to_chat(usr, "You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator.") + if("toggle_fab") + if(!dronefab) + return - src.updateUsrDialog() \ No newline at end of file + if(get_dist(src,dronefab) > 3) + dronefab = null + to_chat(usr, "Unable to locate drone fabricator.") + return + + dronefab.produce_drones = !dronefab.produce_drones + to_chat(usr, "You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator.") diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 02da9be049..d6f5acfb3d 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -38,6 +38,10 @@ drop_item() return +/obj/item/weapon/gripper/AltClick(mob/user) + drop_item() + return + /obj/item/weapon/gripper/omni name = "omni gripper" desc = "A strange grasping tool that can hold anything a human can, but still maintains the limitations of application its more limited cousins have." @@ -252,12 +256,15 @@ return resolved return ..() -/obj/item/weapon/gripper/verb/drop_item() +/obj/item/weapon/gripper/verb/drop_gripper_item() set name = "Drop Item" set desc = "Release an item from your magnetic gripper." set category = "Robot Commands" + drop_item() + +obj/item/weapon/gripper/proc/drop_item() if(!wrapped) //There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z for(var/obj/item/thing in src.contents) @@ -268,7 +275,7 @@ wrapped = null return - to_chat(src.loc, "You drop \the [wrapped].") + to_chat(src.loc, "You drop \the [wrapped].") wrapped.loc = get_turf(src) wrapped = null //update_icon() diff --git a/code/modules/mob/living/silicon/subystems.dm b/code/modules/mob/living/silicon/subystems.dm index e5d50d5824..bb84ed3ce3 100644 --- a/code/modules/mob/living/silicon/subystems.dm +++ b/code/modules/mob/living/silicon/subystems.dm @@ -1,11 +1,11 @@ /mob/living/silicon var/register_alarms = 1 - var/datum/nano_module/alarm_monitor/all/alarm_monitor - var/datum/nano_module/atmos_control/atmos_control + var/datum/tgui_module/alarm_monitor/all/robot/alarm_monitor + var/datum/tgui_module/atmos_control/robot/atmos_control var/datum/tgui_module/crew_monitor/robot/crew_monitor var/datum/nano_module/law_manager/law_manager - var/datum/nano_module/power_monitor/power_monitor - var/datum/nano_module/rcon/rcon + var/datum/tgui_module/power_monitor/robot/power_monitor + var/datum/tgui_module/rcon/robot/rcon /mob/living/silicon var/list/silicon_subsystems = list( @@ -49,7 +49,7 @@ set name = "Alarm Monitor" set category = "Subystems" - alarm_monitor.ui_interact(usr, state = self_state) + alarm_monitor.tgui_interact(usr) /******************** * Atmos Control * @@ -58,7 +58,7 @@ set category = "Subystems" set name = "Atmospherics Control" - atmos_control.ui_interact(usr, state = self_state) + atmos_control.tgui_interact(usr) /******************** * Crew Monitor * @@ -85,7 +85,7 @@ set category = "Subystems" set name = "Power Monitor" - power_monitor.ui_interact(usr, state = self_state) + power_monitor.tgui_interact(usr) /************ * RCON * @@ -94,4 +94,4 @@ set category = "Subystems" set name = "RCON" - rcon.ui_interact(usr, state = self_state) + rcon.tgui_interact(usr) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 2ba4772696..e4327ddc83 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -343,7 +343,7 @@ /mob/proc/set_respawn_timer(var/time) // Try to figure out what time to use - + // Special cases, can never respawn if(ticker?.mode?.deny_respawn) time = -1 @@ -351,22 +351,22 @@ time = -1 else if(!config.respawn) time = -1 - + // Special case for observing before game start else if(ticker?.current_state <= GAME_STATE_SETTING_UP) time = 1 MINUTE - + // Wasn't given a time, use the config time else if(!time) time = config.respawn_time - + var/keytouse = ckey // Try harder to find a key to use if(!keytouse && key) keytouse = ckey(key) else if(!keytouse && mind?.key) keytouse = ckey(mind.key) - + GLOB.respawn_timers[keytouse] = world.time + time /mob/observer/dead/set_respawn_timer() @@ -388,7 +388,7 @@ var/choice = alert(usr, "Returning to the menu will prevent your character from being revived in-round. Are you sure?", "Confirmation", "No, wait", "Yes, leave") if(choice == "No, wait") return - + // Beyond this point, you're going to respawn to_chat(usr, config.respawn_message) @@ -505,6 +505,11 @@ set category = "IC" if(pulling) + if(ishuman(pulling)) + var/mob/living/carbon/human/H = pulling + visible_message(SPAN_WARNING("\The [src] lets go of \the [H]."), SPAN_NOTICE("You let go of \the [H]."), exclude_mobs = list(H)) + if(!H.stat) + to_chat(H, SPAN_WARNING("\The [src] lets go of you.")) pulling.pulledby = null pulling = null if(pullin) @@ -576,6 +581,16 @@ if(ishuman(AM)) var/mob/living/carbon/human/H = AM + if(H.lying) // If they're on the ground we're probably dragging their arms to move them + visible_message(SPAN_WARNING("\The [src] leans down and grips \the [H]'s arms."), SPAN_NOTICE("You lean down and grip \the [H]'s arms."), exclude_mobs = list(H)) + if(!H.stat) + to_chat(H, SPAN_WARNING("\The [src] leans down and grips your arms.")) + else //Otherwise we're probably just holding their arm to lead them somewhere + visible_message(SPAN_WARNING("\The [src] grips \the [H]'s arm."), SPAN_NOTICE("You grip \the [H]'s arm."), exclude_mobs = list(H)) + if(!H.stat) + to_chat(H, SPAN_WARNING("\The [src] grips your arm.")) + playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 25) //Quieter than hugging/grabbing but we still want some audio feedback + if(H.pull_damage()) to_chat(src, "Pulling \the [H] in their current condition would probably be a bad idea.") diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index e6fd555d8d..94c69622c4 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -582,7 +582,6 @@ // Do the initial caching of the player's body icons. new_character.force_update_limbs() new_character.update_icons_body() - new_character.update_eyes() new_character.key = key //Manually transfer the key to log them in diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index a875b8a574..b5b1e205c7 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -1304,6 +1304,35 @@ icon_state = "teshari_mushroom" species_allowed = list(SPECIES_TESHARI) +//Tesh things ported from Ark Station + + teshari_twies + name = "Teshari Twies" + icon_state = "teshari_twies" + species_allowed = list(SPECIES_TESHARI) + + teshari_backstrafe + name = "Teshari Backstrafe" + icon_state = "teshari_backstrafe" + species_allowed = list(SPECIES_TESHARI) + + teshari_longway + name = "Teshari Long way" + icon_state = "teshari_longway" + species_allowed = list(SPECIES_TESHARI) + + teshari_tree + name = "Teshari Tree" + icon_state = "teshari_tree" + species_allowed = list(SPECIES_TESHARI) + + teshari_fluffymohawk + name = "Teshari Fluffy Mohawk" + icon_state = "teshari_fluffymohawk" + species_allowed = list(SPECIES_TESHARI) + +//bald tesh hair for FBP use + teshari_bald name = "Bald (use with FBP)" icon_state = "bald" diff --git a/code/modules/modular_computers/NTNet/NTNet_relay.dm b/code/modules/modular_computers/NTNet/NTNet_relay.dm index 85daf5d03d..9e39fe8e2e 100644 --- a/code/modules/modular_computers/NTNet/NTNet_relay.dm +++ b/code/modules/modular_computers/NTNet/NTNet_relay.dm @@ -57,41 +57,43 @@ ntnet_global.add_log("Quantum relay switched from overload recovery mode to normal operation mode.") ..() -/obj/machinery/ntnet_relay/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) +/obj/machinery/ntnet_relay/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NTNetRelay", src) + ui.open() + +/obj/machinery/ntnet_relay/tgui_data(mob/user) var/list/data = list() data["enabled"] = enabled data["dos_capacity"] = dos_capacity data["dos_overload"] = dos_overload data["dos_crashed"] = dos_failure - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_relay.tmpl", "NTNet Quantum Relay", 500, 300, state = state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data /obj/machinery/ntnet_relay/attack_hand(var/mob/living/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/ntnet_relay/Topic(href, href_list) +/obj/machinery/ntnet_relay/tgui_act(action, params) if(..()) - return 1 - if(href_list["restart"]) - dos_overload = 0 - dos_failure = 0 - update_icon() - ntnet_global.add_log("Quantum relay manually restarted from overload recovery mode to normal operation mode.") - return 1 - else if(href_list["toggle"]) - enabled = !enabled - ntnet_global.add_log("Quantum relay manually [enabled ? "enabled" : "disabled"].") - update_icon() - return 1 - else if(href_list["purge"]) - ntnet_global.banned_nids.Cut() - ntnet_global.add_log("Manual override: Network blacklist cleared.") - return 1 + return TRUE + + switch(action) + if("restart") + dos_overload = 0 + dos_failure = 0 + update_icon() + ntnet_global.add_log("Quantum relay manually restarted from overload recovery mode to normal operation mode.") + . = TRUE + if("toggle") + enabled = !enabled + ntnet_global.add_log("Quantum relay manually [enabled ? "enabled" : "disabled"].") + update_icon() + . = TRUE + if("purge") + ntnet_global.banned_nids.Cut() + ntnet_global.add_log("Manual override: Network blacklist cleared.") + . = TRUE /obj/machinery/ntnet_relay/New() ..() diff --git a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm index 8c03238bff..d7f13fcbc5 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/alarm_monitor filename = "alarmmonitoreng" filedesc = "Alarm Monitoring (Engineering)" - nanomodule_path = /datum/nano_module/alarm_monitor/engineering + tguimodule_path = /datum/tgui_module/alarm_monitor/engineering/ntos ui_header = "alarm_green.gif" program_icon_state = "alert-green" program_key_state = "atmos_key" @@ -15,8 +15,8 @@ /datum/computer_file/program/alarm_monitor/process_tick() ..() - var/datum/nano_module/alarm_monitor/NMA = NM - if(istype(NMA) && NMA.has_major_alarms()) + var/datum/tgui_module/alarm_monitor/TMA = TM + if(istype(TMA) && TMA.has_major_alarms()) if(!has_alert) program_icon_state = "alert-red" ui_header = "alarm_red.gif" @@ -29,112 +29,3 @@ update_computer_icon() has_alert = 0 return 1 - -/datum/nano_module/alarm_monitor - name = "Alarm monitor" - var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use. - var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user. - //available_to_ai = FALSE - -/datum/nano_module/alarm_monitor/New() - ..() - alarm_handlers = list() - -/datum/nano_module/alarm_monitor/all/New() - ..() - alarm_handlers = SSalarm.all_handlers - -/datum/nano_module/alarm_monitor/engineering/New() - ..() - alarm_handlers = list(atmosphere_alarm, fire_alarm, power_alarm) - -/datum/nano_module/alarm_monitor/security/New() - ..() - alarm_handlers = list(camera_alarm, motion_alarm) - -/datum/nano_module/alarm_monitor/proc/register_alarm(var/object, var/procName) - for(var/datum/alarm_handler/AH in alarm_handlers) - AH.register_alarm(object, procName) - -/datum/nano_module/alarm_monitor/proc/unregister_alarm(var/object) - for(var/datum/alarm_handler/AH in alarm_handlers) - AH.unregister_alarm(object) - -/datum/nano_module/alarm_monitor/proc/all_alarms() - var/z = get_z(nano_host()) - var/list/all_alarms = new() - for(var/datum/alarm_handler/AH in alarm_handlers) - all_alarms += AH.visible_alarms(z) - - return all_alarms - -/datum/nano_module/alarm_monitor/proc/major_alarms() - var/z = get_z(nano_host()) - var/list/all_alarms = new() - for(var/datum/alarm_handler/AH in alarm_handlers) - all_alarms += AH.major_alarms(z) - - return all_alarms - -// Modified version of above proc that uses slightly less resources, returns 1 if there is a major alarm, 0 otherwise. -/datum/nano_module/alarm_monitor/proc/has_major_alarms() - var/z = get_z(nano_host()) - for(var/datum/alarm_handler/AH in alarm_handlers) - if(AH.has_major_alarms(z)) - return 1 - - return 0 - -/datum/nano_module/alarm_monitor/proc/minor_alarms() - var/z = get_z(nano_host()) - var/list/all_alarms = new() - for(var/datum/alarm_handler/AH in alarm_handlers) - all_alarms += AH.minor_alarms(z) - - return all_alarms - -/datum/nano_module/alarm_monitor/Topic(ref, href_list) - if(..()) - return 1 - if(href_list["switchTo"]) - var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras - if(!C) - return - - usr.switch_to_camera(C) - return 1 - -/datum/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - var/categories[0] - var/z = get_z(nano_host()) - for(var/datum/alarm_handler/AH in alarm_handlers) - categories[++categories.len] = list("category" = AH.category, "alarms" = list()) - for(var/datum/alarm/A in AH.visible_alarms(z)) - var/cameras[0] - var/lost_sources[0] - - if(isAI(user)) - for(var/obj/machinery/camera/C in A.cameras()) - cameras[++cameras.len] = C.nano_structure() - for(var/datum/alarm_source/AS in A.sources) - if(!AS.source) - lost_sources[++lost_sources.len] = AS.source_name - - categories[categories.len]["alarms"] += list(list( - "name" = sanitize("[A.alarm_name()]" + "[A.max_severity() > 1 ? "(MAJOR)" : ""]"), - "origin_lost" = A.origin == null, - "has_cameras" = cameras.len, - "cameras" = cameras, - "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : "")) - data["categories"] = categories - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state) - if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm b/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm index bfcaadee3e..5c25ed8315 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/atmos_control filename = "atmoscontrol" filedesc = "Atmosphere Control" - nanomodule_path = /datum/nano_module/atmos_control + tguimodule_path = /datum/tgui_module/atmos_control/ntos program_icon_state = "atmos_control" program_key_state = "atmos_key" program_menu_icon = "shuffle" @@ -12,96 +12,3 @@ requires_ntnet_feature = NTNET_SYSTEMCONTROL usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE size = 17 - -/datum/nano_module/atmos_control - name = "Atmospherics Control" - var/obj/access = new() - var/emagged = 0 - var/ui_ref - var/list/monitored_alarms = list() - -/datum/nano_module/atmos_control/New(atmos_computer, req_access, req_one_access, monitored_alarm_ids) - ..() - access.req_access = req_access - access.req_one_access = req_one_access - - if(monitored_alarm_ids) - for(var/obj/machinery/alarm/alarm in machines) - if(alarm.alarm_id && alarm.alarm_id in monitored_alarm_ids) - monitored_alarms += alarm - // machines may not yet be ordered at this point - monitored_alarms = dd_sortedObjectList(monitored_alarms) - -/datum/nano_module/atmos_control/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["alarm"]) - if(ui_ref) - var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms.len ? monitored_alarms : machines) - if(alarm) - var/datum/topic_state/TS = generate_state(alarm) - alarm.ui_interact(usr, master_ui = ui_ref, state = TS) - return 1 - -/datum/nano_module/atmos_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - var/alarms[0] - - var/z = get_z(nano_host()) - var/list/map_levels = using_map.get_map_levels(z) - data["map_levels"] = map_levels - - // TODO: Move these to a cache, similar to cameras - for(var/obj/machinery/alarm/alarm in (monitored_alarms.len ? monitored_alarms : machines)) - if(!monitored_alarms.len && alarm.alarms_hidden) - continue - if(!(alarm.z in map_levels)) - continue - alarms[++alarms.len] = list( - "name" = sanitize(alarm.name), - "ref"= "\ref[alarm]", - "danger" = max(alarm.danger_level, alarm.alarm_area.atmosalm), - "x" = alarm.x, - "y" = alarm.y, - "z" = alarm.z) - data["alarms"] = alarms - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmos_control.tmpl", src.name, 625, 625, state = state) - if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. - ui.auto_update_layout = 1 - // adding a template with the key "mapContent" enables the map ui functionality - ui.add_template("mapContent", "atmos_control_map_content.tmpl") - // adding a template with the key "mapHeader" replaces the map header content - ui.add_template("mapHeader", "atmos_control_map_header.tmpl") - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(0) - ui_ref = ui - -/datum/nano_module/atmos_control/proc/generate_state(air_alarm) - var/datum/topic_state/air_alarm/state = new() - state.atmos_control = src - state.air_alarm = air_alarm - return state - -/datum/topic_state/air_alarm - var/datum/nano_module/atmos_control/atmos_control = null - var/obj/machinery/alarm/air_alarm = null - -/datum/topic_state/air_alarm/can_use_topic(var/src_object, var/mob/user) - if(has_access(user)) - return STATUS_INTERACTIVE - return STATUS_UPDATE - -/datum/topic_state/air_alarm/href_list(var/mob/user) - var/list/extra_href = list() - extra_href["remote_connection"] = 1 - extra_href["remote_access"] = has_access(user) - - return extra_href - -/datum/topic_state/air_alarm/proc/has_access(var/mob/user) - return user && (isAI(user) || atmos_control.access.allowed(user) || atmos_control.emagged || air_alarm.rcon_setting == RCON_YES || (air_alarm.alarm_area.atmosalm && air_alarm.rcon_setting == RCON_AUTO) || (access_ce in user.GetAccess())) diff --git a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm index b5c086dc26..5df437790b 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/power_monitor filename = "powermonitor" filedesc = "Power Monitoring" - nanomodule_path = /datum/nano_module/power_monitor/ + tguimodule_path = /datum/tgui_module/power_monitor/ntos program_icon_state = "power_monitor" program_key_state = "power_key" program_menu_icon = "battery-3" @@ -15,8 +15,8 @@ /datum/computer_file/program/power_monitor/process_tick() ..() - var/datum/nano_module/power_monitor/NMA = NM - if(istype(NMA) && NMA.has_alarm()) + var/datum/tgui_module/power_monitor/TMA = TM + if(istype(TMA) && TMA.has_alarm()) if(!has_alert) program_icon_state = "power_monitor_warn" ui_header = "power_warn.gif" @@ -28,90 +28,3 @@ ui_header = "power_norm.gif" update_computer_icon() has_alert = 0 - -/datum/nano_module/power_monitor - name = "Power monitor" - var/list/grid_sensors - var/active_sensor = null //name_tag of the currently selected sensor - -/datum/nano_module/power_monitor/New() - ..() - refresh_sensors() - -// Checks whether there is an active alarm, if yes, returns 1, otherwise returns 0. -/datum/nano_module/power_monitor/proc/has_alarm() - for(var/obj/machinery/power/sensor/S in grid_sensors) - if(S.check_grid_warning()) - return 1 - return 0 - -// If PC is not null header template is loaded. Use PC.get_header_data() to get relevant nanoui data from it. All data entries begin with "PC_...." -// In future it may be expanded to other modular computer devices. -/datum/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - var/list/sensors = list() - // Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading. - var/obj/machinery/power/sensor/focus = null - - var/z = get_z(nano_host()) - var/list/map_levels = using_map.get_map_levels(z) - data["map_levels"] = map_levels - - // Build list of data from sensor readings. - for(var/obj/machinery/power/sensor/S in grid_sensors) - if(!(S.z in map_levels)) - continue - sensors.Add(list(list( - "name" = S.name_tag, - "alarm" = S.check_grid_warning() - ))) - if(S.name_tag == active_sensor) - focus = S - - data["all_sensors"] = sensors - if(focus) - data["focus"] = focus.return_reading_data() - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 500, state = state) - if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. - ui.auto_update_layout = 1 - // adding a template with the key "mapContent" enables the map ui functionality - ui.add_template("mapContent", "power_monitor_map_content.tmpl") - // adding a template with the key "mapHeader" replaces the map header content - ui.add_template("mapHeader", "power_monitor_map_header.tmpl") - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -// Refreshes list of active sensors kept on this computer. -/datum/nano_module/power_monitor/proc/refresh_sensors() - grid_sensors = list() - var/turf/T = get_turf(nano_host()) - var/list/levels = list() - if(!T) // Safety check - return - if(T) - levels += using_map.get_map_levels(T.z, FALSE) - for(var/obj/machinery/power/sensor/S in machines) - if(T && (S.loc.z == T.z) || (S.loc.z in levels) || (S.long_range)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels. - if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen! - warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z") - else - grid_sensors += S - -// Allows us to process UI clicks, which are relayed in form of hrefs. -/datum/nano_module/power_monitor/Topic(href, href_list) - if(..()) - return 1 - if( href_list["clear"] ) - active_sensor = null - . = 1 - if( href_list["refresh"] ) - refresh_sensors() - . = 1 - else if( href_list["setsensor"] ) - active_sensor = href_list["setsensor"] - . = 1 diff --git a/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm b/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm index 03f69cd949..ded2e3922f 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/rcon_console filename = "rconconsole" filedesc = "RCON Remote Control" - nanomodule_path = /datum/nano_module/rcon + tguimodule_path = /datum/tgui_module/rcon/ntos program_icon_state = "generic" program_key_state = "rd_key" program_menu_icon = "power" @@ -12,129 +12,3 @@ requires_ntnet_feature = NTNET_SYSTEMCONTROL usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE size = 19 - -/datum/nano_module/rcon - name = "Power RCON" - var/list/known_SMESs = null - var/list/known_breakers = null - // Allows you to hide specific parts of the UI - var/hide_SMES = 0 - var/hide_SMES_details = 0 - var/hide_breakers = 0 - -/datum/nano_module/rcon/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1, var/datum/topic_state/state = default_state) - FindDevices() // Update our devices list - var/list/data = host.initial_data() - - // SMES DATA (simplified view) - var/list/smeslist[0] - for(var/obj/machinery/power/smes/buildable/SMES in known_SMESs) - smeslist.Add(list(list( - "charge" = round(SMES.Percentage()), - "input_set" = SMES.input_attempt, - "input_val" = round(SMES.input_level/1000, 0.1), - "output_set" = SMES.output_attempt, - "output_val" = round(SMES.output_level/1000, 0.1), - "output_load" = round(SMES.output_used/1000, 0.1), - "RCON_tag" = SMES.RCon_tag - ))) - - data["smes_info"] = sortByKey(smeslist, "RCON_tag") - - // BREAKER DATA (simplified view) - var/list/breakerlist[0] - for(var/obj/machinery/power/breakerbox/BR in known_breakers) - breakerlist.Add(list(list( - "RCON_tag" = BR.RCon_tag, - "enabled" = BR.on - ))) - data["breaker_info"] = breakerlist - data["hide_smes"] = hide_SMES - data["hide_smes_details"] = hide_SMES_details - data["hide_breakers"] = hide_breakers - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "rcon.tmpl", "RCON Console", 600, 400, state = state) - if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -// Proc: Topic() -// Parameters: 2 (href, href_list - allows us to process UI clicks) -// Description: Allows us to process UI clicks, which are relayed in form of hrefs. -/datum/nano_module/rcon/Topic(href, href_list) - if(..()) - return - - if(href_list["smes_in_toggle"]) - var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_toggle"]) - if(SMES) - SMES.toggle_input() - if(href_list["smes_out_toggle"]) - var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_toggle"]) - if(SMES) - SMES.toggle_output() - if(href_list["smes_in_set"]) - var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_set"]) - if(SMES) - var/inputset = (input(usr, "Enter new input level (0-[SMES.input_level_max/1000] kW)", "SMES Input Power Control", SMES.input_level/1000) as num) * 1000 - SMES.set_input(inputset) - if(href_list["smes_out_set"]) - var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_set"]) - if(SMES) - var/outputset = (input(usr, "Enter new output level (0-[SMES.output_level_max/1000] kW)", "SMES Output Power Control", SMES.output_level/1000) as num) * 1000 - SMES.set_output(outputset) - - if(href_list["toggle_breaker"]) - var/obj/machinery/power/breakerbox/toggle = null - for(var/obj/machinery/power/breakerbox/breaker in known_breakers) - if(breaker.RCon_tag == href_list["toggle_breaker"]) - toggle = breaker - if(toggle) - if(toggle.update_locked) - to_chat(usr, "The breaker box was recently toggled. Please wait before toggling it again.") - else - toggle.auto_toggle() - if(href_list["hide_smes"]) - hide_SMES = !hide_SMES - if(href_list["hide_smes_details"]) - hide_SMES_details = !hide_SMES_details - if(href_list["hide_breakers"]) - hide_breakers = !hide_breakers - - -// Proc: GetSMESByTag() -// Parameters: 1 (tag - RCON tag of SMES we want to look up) -// Description: Looks up and returns SMES which has matching RCON tag -/datum/nano_module/rcon/proc/GetSMESByTag(var/tag) - if(!tag) - return - - for(var/obj/machinery/power/smes/buildable/S in known_SMESs) - if(S.RCon_tag == tag) - return S - -// Proc: FindDevices() -// Parameters: None -// Description: Refreshes local list of known devices. -/datum/nano_module/rcon/proc/FindDevices() - known_SMESs = new /list() - - var/z = get_z(nano_host()) - var/list/map_levels = using_map.get_map_levels(z) - - for(var/obj/machinery/power/smes/buildable/SMES in GLOB.smeses) - if(!(SMES.z in map_levels)) - continue - if(SMES.RCon_tag && (SMES.RCon_tag != "NO_TAG") && SMES.RCon) - known_SMESs.Add(SMES) - - known_breakers = new /list() - for(var/obj/machinery/power/breakerbox/breaker in machines) - if(!(breaker.z in map_levels)) - continue - if(breaker.RCon_tag != "NO_TAG") - known_breakers.Add(breaker) diff --git a/code/modules/modular_computers/file_system/programs/engineering/shutoff_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/shutoff_monitor.dm index c46bb9c667..e87991041e 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/shutoff_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/shutoff_monitor.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/shutoff_monitor filename = "shutoffmonitor" filedesc = "Shutoff Valve Monitoring" - nanomodule_path = /datum/nano_module/shutoff_monitor + tguimodule_path = /datum/tgui_module/shutoff_monitor/ntos program_icon_state = "atmos_control" program_key_state = "atmos_key" program_menu_icon = "wrench" @@ -11,53 +11,3 @@ network_destination = "shutoff valve control computer" size = 5 var/has_alert = 0 - -/datum/nano_module/shutoff_monitor - name = "Shutoff Valve Monitoring" - -/datum/nano_module/shutoff_monitor/Topic(ref, href_list) - if(..()) - return 1 - - if(href_list["toggle_enable"]) - var/obj/machinery/atmospherics/valve/shutoff/S = locate(href_list["toggle_enable"]) - if(!istype(S)) - return 0 - S.close_on_leaks = !S.close_on_leaks - return 1 - - if(href_list["toggle_open"]) - var/obj/machinery/atmospherics/valve/shutoff/S = locate(href_list["toggle_open"]) - if(!istype(S)) - return 0 - if(S.open) - S.close() - else - S.open() - return 1 - -/datum/nano_module/shutoff_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - var/list/valves = list() - - for(var/obj/machinery/atmospherics/valve/shutoff/S in GLOB.shutoff_valves) - valves.Add(list(list( - "name" = S.name, - "enabled" = S.close_on_leaks, - "open" = S.open, - "x" = S.x, - "y" = S.y, - "z" = S.z, - "ref" = "\ref[S]" - ))) - - data["valves"] = valves - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "shutoff_monitor.tmpl", "Shutoff Valve Monitoring", 627, 700, state = state) - if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm index 421bb65047..9c3cabd3f7 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/supermatter_monitor filename = "supmon" filedesc = "Supermatter Monitoring" - nanomodule_path = /datum/nano_module/supermatter_monitor/ + tguimodule_path = /datum/tgui_module/supermatter_monitor/ntos program_icon_state = "smmon_0" program_key_state = "tech_key" program_menu_icon = "notice" @@ -15,119 +15,11 @@ /datum/computer_file/program/supermatter_monitor/process_tick() ..() - var/datum/nano_module/supermatter_monitor/NMS = NM - var/new_status = istype(NMS) ? NMS.get_status() : 0 + var/datum/tgui_module/supermatter_monitor/TMS = TM + var/new_status = istype(TMS) ? TMS.get_status() : 0 if(last_status != new_status) last_status = new_status ui_header = "smmon_[last_status].gif" program_icon_state = "smmon_[last_status]" if(istype(computer)) computer.update_icon() - -/datum/nano_module/supermatter_monitor - name = "Supermatter monitor" - var/list/supermatters - var/obj/machinery/power/supermatter/active = null // Currently selected supermatter crystal. - -/datum/nano_module/supermatter_monitor/Destroy() - . = ..() - active = null - supermatters = null - -/datum/nano_module/supermatter_monitor/New() - ..() - refresh() - -// Refreshes list of active supermatter crystals -/datum/nano_module/supermatter_monitor/proc/refresh() - supermatters = list() - var/z = get_z(nano_host()) - if(!z) - return - var/valid_z_levels = using_map.get_map_levels(z) - for(var/obj/machinery/power/supermatter/S in machines) - // Delaminating, not within coverage, not on a tile. - if(S.grav_pulling || S.exploded || !(S.z in valid_z_levels) || !istype(S.loc, /turf/)) - continue - supermatters.Add(S) - - if(!(active in supermatters)) - active = null - -/datum/nano_module/supermatter_monitor/proc/get_status() - . = SUPERMATTER_INACTIVE - for(var/obj/machinery/power/supermatter/S in supermatters) - . = max(., S.get_status()) - -/datum/nano_module/supermatter_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - if(istype(active)) - var/turf/T = get_turf(active) - if(!T) - active = null - return - var/datum/gas_mixture/air = T.return_air() - if(!istype(air)) - active = null - return - - data["active"] = 1 - data["SM_integrity"] = active.get_integrity() - data["SM_power"] = active.power - data["SM_ambienttemp"] = air.temperature - data["SM_ambientpressure"] = air.return_pressure() - data["SM_EPR"] = active.get_epr() - //data["SM_EPR"] = active.get_epr() - if(air.total_moles) - data["SM_gas_O2"] = round(100*air.gas["oxygen"]/air.total_moles,0.01) - data["SM_gas_CO2"] = round(100*air.gas["carbon_dioxide"]/air.total_moles,0.01) - data["SM_gas_N2"] = round(100*air.gas["nitrogen"]/air.total_moles,0.01) - data["SM_gas_PH"] = round(100*air.gas["phoron"]/air.total_moles,0.01) - data["SM_gas_N2O"] = round(100*air.gas["sleeping_agent"]/air.total_moles,0.01) - else - data["SM_gas_O2"] = 0 - data["SM_gas_CO2"] = 0 - data["SM_gas_N2"] = 0 - data["SM_gas_PH"] = 0 - data["SM_gas_N2O"] = 0 - else - var/list/SMS = list() - for(var/obj/machinery/power/supermatter/S in supermatters) - var/area/A = get_area(S) - if(!A) - continue - - SMS.Add(list(list( - "area_name" = A.name, - "integrity" = S.get_integrity(), - "uid" = S.uid - ))) - - data["active"] = 0 - data["supermatters"] = SMS - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "supermatter_monitor.tmpl", "Supermatter Monitoring", 600, 400, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/nano_module/supermatter_monitor/Topic(href, href_list) - if(..()) - return 1 - if( href_list["clear"] ) - active = null - return 1 - if( href_list["refresh"] ) - refresh() - return 1 - if( href_list["set"] ) - var/newuid = text2num(href_list["set"]) - for(var/obj/machinery/power/supermatter/S in supermatters) - if(S.uid == newuid) - active = S - return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/security/alarm_monitor.dm b/code/modules/modular_computers/file_system/programs/security/alarm_monitor.dm index 2254cc1dae..a833573be6 100644 --- a/code/modules/modular_computers/file_system/programs/security/alarm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/security/alarm_monitor.dm @@ -2,5 +2,5 @@ filename = "alarmmonitorsec" filedesc = "Alarm Monitoring (Security)" extended_desc = "This program provides visual interface for the security alarm system." - nanomodule_path = /datum/nano_module/alarm_monitor/security + tguimodule_path = /datum/tgui_module/alarm_monitor/security/ntos required_access = access_security \ No newline at end of file diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm deleted file mode 100644 index fd2ed900f2..0000000000 --- a/code/modules/nano/modules/human_appearance.dm +++ /dev/null @@ -1,191 +0,0 @@ -/datum/nano_module/appearance_changer - name = "Appearance Editor" - var/flags = APPEARANCE_ALL_HAIR - var/mob/living/carbon/human/owner = null - var/list/valid_species = list() - var/list/valid_hairstyles = list() - var/list/valid_facial_hairstyles = list() - - var/check_whitelist - var/list/whitelist - var/list/blacklist - -/datum/nano_module/appearance_changer/New(var/location, var/mob/living/carbon/human/H, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list()) - ..() - owner = H - src.check_whitelist = check_species_whitelist - src.whitelist = species_whitelist - src.blacklist = species_blacklist - -/datum/nano_module/appearance_changer/Topic(ref, href_list, var/datum/topic_state/state = default_state) - if(..()) - return 1 - - if(href_list["race"]) - if(can_change(APPEARANCE_RACE) && (href_list["race"] in valid_species)) - if(owner.change_species(href_list["race"])) - cut_and_generate_data() - return 1 - if(href_list["gender"]) - if(can_change(APPEARANCE_GENDER) && (href_list["gender"] in get_genders())) - if(owner.change_gender(href_list["gender"])) - cut_and_generate_data() - return 1 - if(href_list["gender_id"]) - if(can_change(APPEARANCE_GENDER) && (href_list["gender_id"] in all_genders_define_list)) - owner.identifying_gender = href_list["gender_id"] - return 1 - if(href_list["skin_tone"]) - if(can_change_skin_tone()) - var/new_s_tone = input(usr, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", -owner.s_tone + 35) as num|null - if(isnum(new_s_tone) && can_still_topic(state)) - new_s_tone = 35 - max(min( round(new_s_tone), 220),1) - return owner.change_skin_tone(new_s_tone) - if(href_list["skin_color"]) - if(can_change_skin_color()) - var/new_skin = input(usr, "Choose your character's skin colour: ", "Skin Color", rgb(owner.r_skin, owner.g_skin, owner.b_skin)) as color|null - if(new_skin && can_still_topic(state)) - var/r_skin = hex2num(copytext(new_skin, 2, 4)) - var/g_skin = hex2num(copytext(new_skin, 4, 6)) - var/b_skin = hex2num(copytext(new_skin, 6, 8)) - if(owner.change_skin_color(r_skin, g_skin, b_skin)) - update_dna() - return 1 - if(href_list["hair"]) - if(can_change(APPEARANCE_HAIR) && (href_list["hair"] in valid_hairstyles)) - if(owner.change_hair(href_list["hair"])) - update_dna() - return 1 - if(href_list["hair_color"]) - if(can_change(APPEARANCE_HAIR_COLOR)) - var/new_hair = input("Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair)) as color|null - if(new_hair && can_still_topic(state)) - var/r_hair = hex2num(copytext(new_hair, 2, 4)) - var/g_hair = hex2num(copytext(new_hair, 4, 6)) - var/b_hair = hex2num(copytext(new_hair, 6, 8)) - if(owner.change_hair_color(r_hair, g_hair, b_hair)) - update_dna() - return 1 - if(href_list["facial_hair"]) - if(can_change(APPEARANCE_FACIAL_HAIR) && (href_list["facial_hair"] in valid_facial_hairstyles)) - if(owner.change_facial_hair(href_list["facial_hair"])) - update_dna() - return 1 - if(href_list["facial_hair_color"]) - if(can_change(APPEARANCE_FACIAL_HAIR_COLOR)) - var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial)) as color|null - if(new_facial && can_still_topic(state)) - var/r_facial = hex2num(copytext(new_facial, 2, 4)) - var/g_facial = hex2num(copytext(new_facial, 4, 6)) - var/b_facial = hex2num(copytext(new_facial, 6, 8)) - if(owner.change_facial_hair_color(r_facial, g_facial, b_facial)) - update_dna() - return 1 - if(href_list["eye_color"]) - if(can_change(APPEARANCE_EYE_COLOR)) - var/new_eyes = input("Please select eye color.", "Eye Color", rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)) as color|null - if(new_eyes && can_still_topic(state)) - var/r_eyes = hex2num(copytext(new_eyes, 2, 4)) - var/g_eyes = hex2num(copytext(new_eyes, 4, 6)) - var/b_eyes = hex2num(copytext(new_eyes, 6, 8)) - if(owner.change_eye_color(r_eyes, g_eyes, b_eyes)) - update_dna() - return 1 - - return 0 - -/datum/nano_module/appearance_changer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - - if(!owner || !owner.species) - return - - generate_data(check_whitelist, whitelist, blacklist) - var/list/data = host.initial_data() - - data["specimen"] = owner.species.name - data["gender"] = owner.gender - data["gender_id"] = owner.identifying_gender - data["change_race"] = can_change(APPEARANCE_RACE) - if(data["change_race"]) - var/species[0] - for(var/specimen in valid_species) - species[++species.len] = list("specimen" = specimen) - data["species"] = species - - data["change_gender"] = can_change(APPEARANCE_GENDER) - if(data["change_gender"]) - var/genders[0] - for(var/gender in get_genders()) - genders[++genders.len] = list("gender_name" = gender2text(gender), "gender_key" = gender) - data["genders"] = genders - var/id_genders[0] - for(var/gender in all_genders_define_list) - id_genders[++id_genders.len] = list("gender_name" = gender2text(gender), "gender_key" = gender) - data["id_genders"] = id_genders - - - data["change_skin_tone"] = can_change_skin_tone() - data["change_skin_color"] = can_change_skin_color() - data["change_eye_color"] = can_change(APPEARANCE_EYE_COLOR) - data["change_hair"] = can_change(APPEARANCE_HAIR) - if(data["change_hair"]) - var/hair_styles[0] - for(var/hair_style in valid_hairstyles) - hair_styles[++hair_styles.len] = list("hairstyle" = hair_style) - data["hair_styles"] = hair_styles - data["hair_style"] = owner.h_style - - data["change_facial_hair"] = can_change(APPEARANCE_FACIAL_HAIR) - if(data["change_facial_hair"]) - var/facial_hair_styles[0] - for(var/facial_hair_style in valid_facial_hairstyles) - facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_style) - data["facial_hair_styles"] = facial_hair_styles - data["facial_hair_style"] = owner.f_style - - data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR) - data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "appearance_changer.tmpl", "[src]", 800, 450, state = state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/nano_module/appearance_changer/proc/update_dna() - if(owner && (flags & APPEARANCE_UPDATE_DNA)) - owner.update_dna() - -/datum/nano_module/appearance_changer/proc/can_change(var/flag) - return owner && (flags & flag) - -/datum/nano_module/appearance_changer/proc/can_change_skin_tone() - return owner && (flags & APPEARANCE_SKIN) && owner.species.appearance_flags & HAS_SKIN_TONE - -/datum/nano_module/appearance_changer/proc/can_change_skin_color() - return owner && (flags & APPEARANCE_SKIN) && owner.species.appearance_flags & HAS_SKIN_COLOR - -/datum/nano_module/appearance_changer/proc/cut_and_generate_data() - // Making the assumption that the available species remain constant - valid_facial_hairstyles.Cut() - valid_facial_hairstyles.Cut() - generate_data() - -/datum/nano_module/appearance_changer/proc/generate_data() - if(!owner) - return - if(!valid_species.len) - valid_species = owner.generate_valid_species(check_whitelist, whitelist, blacklist) - if(!valid_hairstyles.len || !valid_facial_hairstyles.len) - valid_hairstyles = owner.generate_valid_hairstyles(check_gender = 0) - valid_facial_hairstyles = owner.generate_valid_facial_hairstyles() - - -/datum/nano_module/appearance_changer/proc/get_genders() - var/datum/species/S = owner.species - var/list/possible_genders = S.genders - if(!owner.internal_organs_by_name["cell"]) - return possible_genders - possible_genders = possible_genders.Copy() - possible_genders |= NEUTER - return possible_genders \ No newline at end of file diff --git a/code/modules/nifsoft/software/06_screens.dm b/code/modules/nifsoft/software/06_screens.dm index 64a1faac5c..8dadc88192 100644 --- a/code/modules/nifsoft/software/06_screens.dm +++ b/code/modules/nifsoft/software/06_screens.dm @@ -34,19 +34,19 @@ access = access_engine cost = 625 p_drain = 0.025 - var/datum/nano_module/alarm_monitor/engineering/arscreen + var/datum/tgui_module/alarm_monitor/engineering/nif/tgarscreen New() ..() - arscreen = new(nif) + tgarscreen = new(nif) Destroy() - QDEL_NULL(arscreen) + QDEL_NULL(tgarscreen) return ..() activate() if((. = ..())) - arscreen.ui_interact(nif.human,"main",null,1,nif_state) + tgarscreen.tgui_interact(nif.human) return TRUE deactivate() diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index cf1f251307..3d12e68534 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -36,12 +36,8 @@ to_chat(user, "You put [P] in [src].") user.drop_item() P.loc = src - icon_state = "[initial(icon_state)]-open" - flick("[initial(icon_state)]-open",src) - playsound(src, 'sound/bureaucracy/filingcabinet.ogg', 50, 1) - sleep(40) - icon_state = initial(icon_state) - updateUsrDialog() + open_animation() + SStgui.update_uis(src) else if(P.is_wrench()) playsound(src, P.usesound, 50, 1) anchored = !anchored @@ -65,20 +61,12 @@ to_chat(user, "\The [src] is empty.") return - user.set_machine(src) - var/dat = "
" - for(var/obj/item/P in src) - dat += "" - dat += "
[P.name]
" - user << browse("[name][dat]", "window=filingcabinet;size=350x300") - - return + tgui_interact(user) /obj/structure/filingcabinet/attack_tk(mob/user) if(anchored) - attack_self_tk(user) - else - ..() + return attack_self_tk(user) + return ..() /obj/structure/filingcabinet/attack_self_tk(mob/user) if(contents.len) @@ -91,20 +79,46 @@ return to_chat(user, "You find nothing in [src].") -/obj/structure/filingcabinet/Topic(href, href_list) - if(href_list["retrieve"]) - usr << browse("", "window=filingcabinet") // Close the menu +/obj/structure/filingcabinet/tgui_state(mob/user) + return GLOB.tgui_physical_state - //var/retrieveindex = text2num(href_list["retrieve"]) - var/obj/item/P = locate(href_list["retrieve"])//contents[retrieveindex] - if(istype(P) && (P.loc == src) && src.Adjacent(usr)) - usr.put_in_hands(P) - updateUsrDialog() - flick("[initial(icon_state)]-open",src) - playsound(src, 'sound/bureaucracy/filingcabinet.ogg', 50, 1) - spawn(0) - sleep(20) - icon_state = initial(icon_state) +/obj/structure/filingcabinet/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "FileCabinet", name) + ui.set_autoupdate(FALSE) + ui.open() + +/obj/structure/filingcabinet/tgui_data(mob/user) + var/list/data = list() + + data["contents"] = list() + for(var/obj/item/P in src) + data["contents"].Add(list(list( + "name" = P.name, + "ref" = "\ref[P]", + ))) + + return data + +/obj/structure/filingcabinet/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("retrieve") + var/obj/item/P = locate(params["ref"]) + if(istype(P) && (P.loc == src) && usr.Adjacent(src)) + usr.put_in_hands(P) + open_animation() + SStgui.update_uis(src) + +/obj/structure/filingcabinet/proc/open_animation() + flick("[initial(icon_state)]-open",src) + playsound(src, 'sound/bureaucracy/filingcabinet.ogg', 50, 1) + spawn(0) + sleep(20) + icon_state = initial(icon_state) /* * Security Record Cabinets @@ -112,7 +126,6 @@ /obj/structure/filingcabinet/security var/virgin = 1 - /obj/structure/filingcabinet/security/proc/populate() if(virgin) for(var/datum/data/record/G in data_core.general) diff --git a/code/modules/persistence/graffiti.dm b/code/modules/persistence/graffiti.dm index d6a56b75f1..ee1a1b7fce 100644 --- a/code/modules/persistence/graffiti.dm +++ b/code/modules/persistence/graffiti.dm @@ -39,10 +39,10 @@ to_chat(user, "It reads \"[message]\".") /obj/effect/decal/writing/attackby(var/obj/item/thing, var/mob/user) - if(is_hot(thing)) + if(istype(thing, /obj/item/weapon/weldingtool)) var/obj/item/weapon/weldingtool/welder = thing if(welder.isOn() && welder.remove_fuel(0,user) && do_after(user, 5, src) && !QDELETED(src)) - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + playsound(src.loc, welder.usesound, 50, 1) user.visible_message("\The [user] clears away some graffiti.") qdel(src) else if(thing.sharp) @@ -61,4 +61,4 @@ if(lowertext(message) == "elbereth") to_chat(user, "You feel much safer.") else - . = ..() \ No newline at end of file + . = ..() diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 1dd8e6a133..90ba2d1a36 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -27,9 +27,19 @@ GLOBAL_LIST_EMPTY(apcs) #define APC_UPOVERLAY_LOCKED 4096 #define APC_UPOVERLAY_OPERATING 8192 - #define APC_UPDATE_ICON_COOLDOWN 100 // 10 seconds +// main_status var +#define APC_EXTERNAL_POWER_NOTCONNECTED 0 +#define APC_EXTERNAL_POWER_NOENERGY 1 +#define APC_EXTERNAL_POWER_GOOD 2 + +// has_electronics var +#define APC_HAS_ELECTRONICS_NONE 0 +#define APC_HAS_ELECTRONICS_WIRED 1 +#define APC_HAS_ELECTRONICS_SECURED 2 + + // the Area Power Controller (APC), formerly Power Distribution Unit (PDU) // one per area, needs wire conection to power network through a terminal @@ -101,13 +111,13 @@ GLOBAL_LIST_EMPTY(apcs) var/lastused_environ = 0 var/lastused_charging = 0 var/lastused_total = 0 - var/main_status = 0 + var/main_status = APC_EXTERNAL_POWER_NOTCONNECTED var/mob/living/silicon/ai/hacker = null // Malfunction var. If set AI hacked the APC and has full control. var/wiresexposed = 0 powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :( var/debug= 0 var/autoflag= 0 // 0 = off, 1= eqp and lights off, 2 = eqp off, 3 = all on. - var/has_electronics = 0 // 0 - none, 1 - plugged in, 2 - secured by screwdriver + var/has_electronics = APC_HAS_ELECTRONICS_NONE // 0 - none, 1 - plugged in, 2 - secured by screwdriver var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment var/longtermpower = 10 var/datum/wires/apc/wires = null @@ -131,7 +141,7 @@ GLOBAL_LIST_EMPTY(apcs) var/last_nightshift_switch = 0 /obj/machinery/power/apc/updateDialog() - if (stat & (BROKEN|MAINT)) + if(stat & (BROKEN|MAINT)) return ..() @@ -175,12 +185,12 @@ GLOBAL_LIST_EMPTY(apcs) // offset 24 pixels in direction of dir // this allows the APC to be embedded in a wall, yet still inside an area - if (building) + if(building) set_dir(ndir) - pixel_x = (src.dir & 3)? 0 : (src.dir == 4 ? 26 : -26) //VOREStation Edit -> 24 to 26 - pixel_y = (src.dir & 3)? (src.dir ==1 ? 26 : -26) : 0 //VOREStation Edit -> 24 to 26 - if (building==0) + pixel_x = (dir & 3)? 0 : (dir == 4 ? 26 : -26) //VOREStation Edit -> 24 to 26 + pixel_y = (dir & 3)? (dir ==1 ? 26 : -26) : 0 //VOREStation Edit -> 24 to 26 + if(building==0) init() else area = get_area(src) @@ -189,11 +199,11 @@ GLOBAL_LIST_EMPTY(apcs) operating = 0 name = "[area.name] APC" stat |= MAINT - src.update_icon() + update_icon() /obj/machinery/power/apc/Destroy() GLOB.apcs -= src - src.update() + update() area.apc = null area.power_light = 0 area.power_equip = 0 @@ -216,11 +226,11 @@ GLOBAL_LIST_EMPTY(apcs) // APCs are pixel-shifted, so they need to be updated. /obj/machinery/power/apc/set_dir(new_dir) ..() - pixel_x = (src.dir & 3)? 0 : (src.dir == 4 ? 24 : -24) - pixel_y = (src.dir & 3)? (src.dir ==1 ? 24 : -24) : 0 + pixel_x = (dir & 3)? 0 : (dir == 4 ? 24 : -24) + pixel_y = (dir & 3)? (dir ==1 ? 24 : -24) : 0 if(terminal) terminal.disconnect_from_network() - terminal.set_dir(src.dir) // Terminal has same dir as master + terminal.set_dir(dir) // Terminal has same dir as master terminal.connect_to_network() // Refresh the network the terminal is connected to. return @@ -230,25 +240,25 @@ GLOBAL_LIST_EMPTY(apcs) /obj/machinery/power/apc/proc/make_terminal() // create a terminal object at the same position as original turf loc // wires will attach to this - terminal = new/obj/machinery/power/terminal(src.loc) + terminal = new/obj/machinery/power/terminal(loc) terminal.set_dir(dir) terminal.master = src /obj/machinery/power/apc/proc/init() - has_electronics = 2 //installed and secured + has_electronics = APC_HAS_ELECTRONICS_SECURED //installed and secured // is starting with a power cell installed, create it and set its charge level if(cell_type) - src.cell = new cell_type(src) + cell = new cell_type(src) cell.charge = start_charge * cell.maxcharge / 100.0 // (convert percentage to actual value) - var/area/A = src.loc.loc + var/area/A = loc.loc //if area isn't specified use current - if(isarea(A) && src.areastring == null) - src.area = A + if(isarea(A) && !areastring) + area = A name = "\improper [area.name] APC" else - src.area = get_area_name(areastring) + area = get_area_name(areastring) name = "\improper [area.name] APC" area.apc = src @@ -260,7 +270,7 @@ GLOBAL_LIST_EMPTY(apcs) make_terminal() spawn(5) - src.update() + update() /obj/machinery/power/apc/examine(mob/user) . = ..() @@ -271,17 +281,17 @@ GLOBAL_LIST_EMPTY(apcs) else if(opened) if(has_electronics && terminal) . += "The cover is [opened == 2 ? "removed" : "open"] and [ cell ? "a power cell is installed" : "the power cell is missing"]." - else if (!has_electronics && terminal) + else if(!has_electronics && terminal) . += "The frame is wired, but the electronics are missing." - else if (has_electronics && !terminal) + else if(has_electronics && !terminal) . += "The electronics are installed, but not wired." - else /* if (!has_electronics && !terminal) */ + else /* if(!has_electronics && !terminal) */ . += "It's just an empty metal frame." else - if (wiresexposed) + if(wiresexposed) . += "The cover is closed and the wires are exposed." - else if ((locked && emagged) || hacker) //Some things can cause locked && emagged. Malf AI causes hacker. + else if((locked && emagged) || hacker) //Some things can cause locked && emagged. Malf AI causes hacker. . += "The cover is closed, but the panel is unresponsive." else if(!locked && emagged) //Normal emag does this. . += "The cover is closed, but the panel is flashing an error." @@ -292,7 +302,7 @@ GLOBAL_LIST_EMPTY(apcs) // update the APC icon to show the three base states // also add overlays for indicator lights /obj/machinery/power/apc/update_icon() - if (!status_overlays) + if(!status_overlays) status_overlays = 1 status_overlays_lock = new status_overlays_charging = new @@ -424,7 +434,7 @@ GLOBAL_LIST_EMPTY(apcs) else if(charging == 2) update_overlay |= APC_UPOVERLAY_CHARGEING2 - if (!equipment) + if(!equipment) update_overlay |= APC_UPOVERLAY_EQUIPMENT0 else if(equipment == 1) update_overlay |= APC_UPOVERLAY_EQUIPMENT1 @@ -468,35 +478,34 @@ GLOBAL_LIST_EMPTY(apcs) //attack with an item - open/close cover, insert cell, or (un)lock interface /obj/machinery/power/apc/attackby(obj/item/W, mob/user) - - if (istype(user, /mob/living/silicon) && get_dist(src,user)>1) - return src.attack_hand(user) - src.add_fingerprint(user) - if (W.is_crowbar() && opened) - if (has_electronics==1) - if (terminal) + if(issilicon(user) && get_dist(src,user) > 1) + return attack_hand(user) + add_fingerprint(user) + if(W.is_crowbar() && opened) + if(has_electronics == APC_HAS_ELECTRONICS_WIRED) + if(terminal) to_chat(user, "Disconnect the wires first.") return playsound(src, W.usesound, 50, 1) to_chat(user, "You begin to remove the power control board...") //lpeters - fixed grammar issues //Ner - grrrrrr if(do_after(user, 50 * W.toolspeed)) - if (has_electronics==1) - has_electronics = 0 - if ((stat & BROKEN)) + if(has_electronics == APC_HAS_ELECTRONICS_WIRED) + has_electronics = APC_HAS_ELECTRONICS_NONE + if((stat & BROKEN)) user.visible_message(\ - "[user.name] has broken the charred power control board inside [src.name]!",\ + "[user.name] has broken the charred power control board inside [name]!",\ "You broke the charred power control board and remove the remains.", "You hear a crack!") //ticker.mode:apcs-- //XSI said no and I agreed. -rastaf0 else user.visible_message(\ - "[user.name] has removed the power control board from [src.name]!",\ + "[user.name] has removed the power control board from [name]!",\ "You remove the power control board.") new /obj/item/weapon/module/power_control(loc) - else if (opened!=2) //cover isn't removed + else if(opened != 2) //cover isn't removed opened = 0 update_icon() - else if (W.is_crowbar() && !(stat & BROKEN) ) + else if(W.is_crowbar() && !(stat & BROKEN) ) if(coverlocked && !(stat & MAINT)) to_chat(user, "The cover is locked and cannot be opened.") return @@ -505,9 +514,9 @@ GLOBAL_LIST_EMPTY(apcs) update_icon() else if (istype(W, /obj/item/weapon/cell) && opened) // trying to put a cell inside if(cell) - to_chat(user, "The [src.name] already has a power cell installed.") + to_chat(user, "The [name] already has a power cell installed.") return - if (stat & MAINT) + if(stat & MAINT) to_chat(user, "You need to install the wiring and electronics first.") return if(W.w_class != ITEMSIZE_NORMAL) @@ -518,27 +527,27 @@ GLOBAL_LIST_EMPTY(apcs) W.forceMove(src) cell = W user.visible_message(\ - "[user.name] has inserted a power cell into [src.name]!",\ + "[user.name] has inserted a power cell into [name]!",\ "You insert the power cell.") chargecount = 0 update_icon() else if (W.is_screwdriver()) // haxing if(opened) - if (cell) + if(cell) to_chat(user, "Remove the power cell first.") return else - if (has_electronics==1 && terminal) - has_electronics = 2 + if(has_electronics == APC_HAS_ELECTRONICS_WIRED && terminal) + has_electronics = APC_HAS_ELECTRONICS_SECURED stat &= ~MAINT playsound(src, W.usesound, 50, 1) to_chat(user, "You screw the circuit electronics into place.") - else if (has_electronics==2) - has_electronics = 1 + else if(has_electronics == APC_HAS_ELECTRONICS_SECURED) + has_electronics = APC_HAS_ELECTRONICS_WIRED stat |= MAINT playsound(src, W.usesound, 50, 1) to_chat(user, "You unfasten the electronics.") - else /* has_electronics==0 */ + else /* has_electronics == APC_HAS_ELECTRONICS_NONE */ to_chat(user, "There is nothing to secure.") return update_icon() @@ -548,10 +557,10 @@ GLOBAL_LIST_EMPTY(apcs) playsound(src, W.usesound, 50, 1) update_icon() - else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) // trying to unlock the interface with an ID card - togglelock() + else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) // trying to unlock the interface with an ID card + togglelock(user) - else if (istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics!=2) + else if(istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics != APC_HAS_ELECTRONICS_SECURED) var/turf/T = loc if(istype(T) && !T.is_plating()) to_chat(user, "You must remove the floor plating in front of the APC first.") @@ -564,9 +573,9 @@ GLOBAL_LIST_EMPTY(apcs) "You start adding cables to the APC frame...") playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) if(do_after(user, 20)) - if (C.amount >= 10 && !terminal && opened && has_electronics != 2) + if(C.amount >= 10 && !terminal && opened && has_electronics != APC_HAS_ELECTRONICS_SECURED) var/obj/structure/cable/N = T.get_cable_node() - if (prob(50) && electrocute_mob(usr, N, N)) + if(prob(50) && electrocute_mob(usr, N, N)) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(5, 1, src) s.start() @@ -578,7 +587,7 @@ GLOBAL_LIST_EMPTY(apcs) "You add cables to the APC frame.") make_terminal() terminal.connect_to_network() - else if (W.is_wirecutter() && terminal && opened && has_electronics!=2) + else if(W.is_wirecutter() && terminal && opened && has_electronics != APC_HAS_ELECTRONICS_SECURED) var/turf/T = loc if(istype(T) && !T.is_plating()) to_chat(user, "You must remove the floor plating in front of the APC first.") @@ -587,8 +596,8 @@ GLOBAL_LIST_EMPTY(apcs) "You begin to cut the cables...") playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) if(do_after(user, 50 * W.toolspeed)) - if(terminal && opened && has_electronics!=2) - if (prob(50) && electrocute_mob(usr, terminal.powernet, terminal)) + if(terminal && opened && has_electronics != APC_HAS_ELECTRONICS_SECURED) + if(prob(50) && electrocute_mob(usr, terminal.powernet, terminal)) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(5, 1, src) s.start() @@ -597,22 +606,22 @@ GLOBAL_LIST_EMPTY(apcs) new /obj/item/stack/cable_coil(loc,10) to_chat(user, "You cut the cables and dismantle the power terminal.") qdel(terminal) - else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && !((stat & BROKEN))) + else if(istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics == APC_HAS_ELECTRONICS_NONE && !((stat & BROKEN))) user.visible_message("[user.name] inserts the power control board into [src].", \ "You start to insert the power control board into the frame...") playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) if(do_after(user, 10)) - if(has_electronics==0) - has_electronics = 1 + if(has_electronics == APC_HAS_ELECTRONICS_NONE) + has_electronics = APC_HAS_ELECTRONICS_WIRED reboot() to_chat(user, "You place the power control board inside the frame.") qdel(W) - else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && ((stat & BROKEN))) + else if(istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics == APC_HAS_ELECTRONICS_NONE && ((stat & BROKEN))) to_chat(user, "The [src] is too broken for that. Repair it first.") return - else if (istype(W, /obj/item/weapon/weldingtool) && opened && has_electronics==0 && !terminal) + else if(istype(W, /obj/item/weapon/weldingtool) && opened && has_electronics == APC_HAS_ELECTRONICS_NONE && !terminal) var/obj/item/weapon/weldingtool/WT = W - if (WT.get_fuel() < 3) + if(WT.get_fuel() < 3) to_chat(user, "You need more welding fuel to complete this task.") return user.visible_message("[user.name] begins cutting apart [src] with the [WT.name].", \ @@ -621,7 +630,7 @@ GLOBAL_LIST_EMPTY(apcs) playsound(src, WT.usesound, 25, 1) if(do_after(user, 50 * WT.toolspeed)) if(!src || !WT.remove_fuel(3, user)) return - if (emagged || (stat & BROKEN) || opened==2) + if(emagged || (stat & BROKEN) || opened==2) new /obj/item/stack/material/steel(loc) user.visible_message(\ "[src] has been cut apart by [user.name] with the [WT.name].",\ @@ -635,8 +644,8 @@ GLOBAL_LIST_EMPTY(apcs) "You hear welding.") qdel(src) return - else if (opened && ((stat & BROKEN) || hacker || emagged)) - if (istype(W, /obj/item/frame/apc) && (stat & BROKEN)) + else if(opened && ((stat & BROKEN) || hacker || emagged)) + if(istype(W, /obj/item/frame/apc) && (stat & BROKEN)) if(cell) to_chat(user, "You need to remove the power cell first.") return @@ -648,10 +657,10 @@ GLOBAL_LIST_EMPTY(apcs) qdel(W) stat &= ~BROKEN reboot() - if (opened==2) + if(opened==2) opened = 1 update_icon() - else if (istype(W, /obj/item/device/multitool) && (hacker || emagged)) + else if(istype(W, /obj/item/device/multitool) && (hacker || emagged)) if(cell) to_chat(user, "You need to remove the power cell first.") return @@ -663,12 +672,12 @@ GLOBAL_LIST_EMPTY(apcs) playsound(src, 'sound/machines/chime.ogg', 25, 1) reboot() else - if ((stat & BROKEN) \ + if((stat & BROKEN) \ && !opened \ && W.force >= 5 \ && W.w_class >= ITEMSIZE_SMALL ) - user.visible_message("The [src.name] has been hit with the [W.name] by [user.name]!", \ - "You hit the [src.name] with your [W.name]!", \ + user.visible_message("The [name] has been hit with the [W.name] by [user.name]!", \ + "You hit the [name] with your [W.name]!", \ "You hear a bang!") if(prob(20)) opened = 2 @@ -677,12 +686,12 @@ GLOBAL_LIST_EMPTY(apcs) "You hear a bang!") update_icon() else - if (istype(user, /mob/living/silicon)) - return src.attack_hand(user) - if (!opened && wiresexposed && (istype(W, /obj/item/device/multitool) || W.is_wirecutter() || istype(W, /obj/item/device/assembly/signaler))) - return src.attack_hand(user) + if(istype(user, /mob/living/silicon)) + return attack_hand(user) + if(!opened && wiresexposed && (istype(W, /obj/item/device/multitool) || W.is_wirecutter() || istype(W, /obj/item/device/assembly/signaler))) + return attack_hand(user) //Placeholder until someone can do take_damage() for APCs or something. - to_chat(user, "The [src.name] looks too sturdy to bash open with \the [W.name].") + to_chat(user, "The [name] looks too sturdy to bash open with \the [W.name].") // attack with hand - remove cell (if cover open) or interact with the APC @@ -698,7 +707,7 @@ GLOBAL_LIST_EMPTY(apcs) else if(hacker) to_chat(user, "Access denied.") else - if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN)) + if(allowed(user) && !wires.is_cut(WIRE_IDSCAN)) locked = !locked to_chat(user, "You [ locked ? "lock" : "unlock"] the APC interface.") update_icon() @@ -707,10 +716,10 @@ GLOBAL_LIST_EMPTY(apcs) /obj/machinery/power/apc/AltClick(mob/user) ..() - togglelock() + togglelock(user) /obj/machinery/power/apc/emag_act(var/remaining_charges, var/mob/user) - if (!(emagged || hacker)) // trying to unlock with an emag card + if(!(emagged || hacker)) // trying to unlock with an emag card if(opened) to_chat(user, "You must close the cover to do that.") else if(wiresexposed) @@ -719,7 +728,7 @@ GLOBAL_LIST_EMPTY(apcs) to_chat(user, "The [src] isn't working.") else flick("apc-spark", src) - if (do_after(user,6)) + if(do_after(user,6)) emagged = 1 locked = 0 to_chat(user, "You emag the APC interface.") @@ -733,11 +742,9 @@ GLOBAL_LIST_EMPTY(apcs) update_icon() /obj/machinery/power/apc/attack_hand(mob/user) -// if (!can_use(user)) This already gets called in interact() and in topic() -// return if(!user) return - src.add_fingerprint(user) + add_fingerprint(user) //Human mob special interaction goes here. if(istype(user,/mob/living/carbon/human)) @@ -745,20 +752,20 @@ GLOBAL_LIST_EMPTY(apcs) if(H.species.can_shred(H)) user.setClickCooldown(user.get_attack_speed()) - user.visible_message("[user.name] slashes at the [src.name]!", "You slash at the [src.name]!") + user.visible_message("[user.name] slashes at the [name]!", "You slash at the [name]!") playsound(src, 'sound/weapons/slash.ogg', 100, 1) var/allcut = wires.is_all_cut() if(beenhit >= pick(3, 4) && wiresexposed != 1) wiresexposed = 1 - src.update_icon() - src.visible_message("The [src.name]'s cover flies open, exposing the wires!") + update_icon() + visible_message("The [name]'s cover flies open, exposing the wires!") else if(wiresexposed == 1 && allcut == 0) wires.cut_all() - src.update_icon() - src.visible_message("The [src.name]'s wires are shredded!") + update_icon() + visible_message("The [name]'s wires are shredded!") else beenhit += 1 return @@ -769,16 +776,21 @@ GLOBAL_LIST_EMPTY(apcs) cell.add_fingerprint(user) cell.update_icon() - src.cell = null - user.visible_message("[user.name] removes the power cell from [src.name]!",\ + cell = null + user.visible_message("[user.name] removes the power cell from [name]!",\ "You remove the power cell.") charging = 0 - src.update_icon() + update_icon() return if(stat & (BROKEN|MAINT)) return // do APC interaction - src.interact(user) + interact(user) + +/obj/machinery/power/apc/attack_ghost(mob/user) + if(panel_open) + return wires.Interact(user) + return tgui_interact(user) /obj/machinery/power/apc/interact(mob/user) if(!user) @@ -788,15 +800,18 @@ GLOBAL_LIST_EMPTY(apcs) wires.Interact(user) return //The panel is visibly dark when the wires are exposed, so we shouldn't be able to interact with it. - return ui_interact(user) + return tgui_interact(user) +/obj/machinery/power/apc/tgui_interact(mob/user, datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "APC", name) // 510, 460 + ui.open() -/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(!user) - return - +/obj/machinery/power/apc/tgui_data(mob/user) var/list/data = list( "locked" = locked, + "normallyLocked" = locked, "emagged" = emagged, "isOperating" = operating, "externalPower" = main_status, @@ -808,7 +823,7 @@ GLOBAL_LIST_EMPTY(apcs) "failTime" = failure_timer * 2, "gridCheck" = grid_check, "coverLocked" = coverlocked, - "siliconUser" = issilicon(user) || isobserver(user), //I add observer here so admins can have more control, even if it makes 'siliconUser' seem inaccurate. + "siliconUser" = issilicon(user) || (isobserver(user) && is_admin(user)), //I add observer here so admins can have more control, even if it makes 'siliconUser' seem inaccurate. "emergencyLights" = !emergency_lights, "nightshiftLights" = nightshift_lights, "nightshiftSetting" = nightshift_setting, @@ -847,18 +862,7 @@ GLOBAL_LIST_EMPTY(apcs) ) ) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 490 : 465) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + return data /obj/machinery/power/apc/proc/report() return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])" @@ -868,23 +872,23 @@ GLOBAL_LIST_EMPTY(apcs) area.power_light = (lighting >= POWERCHAN_ON) area.power_equip = (equipment >= POWERCHAN_ON) area.power_environ = (environ >= POWERCHAN_ON) -// if (area.name == "AI Chamber") +// if(area.name == "AI Chamber") // spawn(10) // to_world(" [area.name] [area.power_equip]") else area.power_light = 0 area.power_equip = 0 area.power_environ = 0 -// if (area.name == "AI Chamber") +// if(area.name == "AI Chamber") // to_world("[area.power_equip]") area.power_change() /obj/machinery/power/apc/proc/can_use(mob/user as mob, var/loud = 0) //used by attack_hand() and Topic() if(!user.client) return 0 - if(isobserver(user) && is_admin(user) ) //This is to allow nanoUI interaction by ghost admins. + if(isobserver(user) && is_admin(user)) //This is to allow nanoUI interaction by ghost admins. return 1 - if (user.stat) + if(user.stat) return 0 if(inoperable()) return 0 @@ -897,7 +901,7 @@ GLOBAL_LIST_EMPTY(apcs) to_chat(user, "You must stand to use [src]!") return 0 autoflag = 5 - if (istype(user, /mob/living/silicon)) + if(istype(user, /mob/living/silicon)) var/permit = 0 // Malfunction variable. If AI hacks APC it can control it even without AI control wire. var/mob/living/silicon/ai/AI = user var/mob/living/silicon/robot/robot = user @@ -912,122 +916,90 @@ GLOBAL_LIST_EMPTY(apcs) to_chat(user, "\The AI control for [src] has been disabled!") return 0 else - if (!in_range(src, user) || !istype(src.loc, /turf)) + if(!in_range(src, user) || !istype(loc, /turf)) return 0 var/mob/living/carbon/human/H = user - if (istype(H) && prob(H.getBrainLoss())) + if(istype(H) && prob(H.getBrainLoss())) to_chat(user, "You momentarily forget how to use [src].") return 0 return 1 -/obj/machinery/power/apc/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/power/apc/tgui_act(action, params) + if(..() || !can_use(usr, TRUE)) + return TRUE - if(!can_use(usr, 1)) - return 1 + // There's a handful of cases where we want to allow users to bypass the `locked` variable. + // If can_admin_interact() wasn't only defined on observers, this could just be part of a single-line + // conditional. + var/locked_exception = FALSE + if(issilicon(usr) || action == "nightshift") + locked_exception = TRUE + if(isobserver(usr)) + var/mob/observer/dead/D = usr + if(D.can_admin_interact()) + locked_exception = TRUE - if(href_list["nightshift"]) - if(last_nightshift_switch > world.time - 10 SECONDS) // don't spam... - to_chat(usr, "[src]'s night lighting circuit breaker is still cycling!") - return 0 - last_nightshift_switch = world.time - nightshift_setting = text2num(href_list["nightshift"]) - update_nightshift() - return 1 + if(locked && !locked_exception) + return - if(locked && !issilicon(usr) ) - if(isobserver(usr) ) - var/mob/observer/dead/O = usr //Added to allow admin nanoUI interactions. - if(!O.can_admin_interact() ) //NanoUI /should/ make this not needed, but better safe than sorry. - to_chat(usr, "Try as you might, your ghostly fingers can't press the buttons.") - return 1 - else - to_chat(usr, "You must unlock the panel to use this!") - return 1 - - if (href_list["lock"]) - coverlocked = !coverlocked - - else if (href_list["reboot"]) - failure_timer = 0 - update_icon() - update() - - else if (href_list["emergency_lighting"]) - emergency_lights = !emergency_lights - for(var/obj/machinery/light/L in area) - if(!initial(L.no_emergency)) //If there was an override set on creation, keep that override - L.no_emergency = emergency_lights - INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE) - CHECK_TICK - - else if (href_list["breaker"]) - toggle_breaker() - - else if (href_list["cmode"]) - chargemode = !chargemode - if(!chargemode) - charging = 0 + . = TRUE + switch(action) + if("lock") + if(locked_exception) // Yay code reuse + if(emagged || (stat & (BROKEN|MAINT))) + to_chat(usr, "The APC does not respond to the command.") + return + locked = !locked + update_icon() + if("cover") + coverlocked = !coverlocked + if("breaker") + toggle_breaker() + if("nightshift") + if(last_nightshift_switch > world.time - 10 SECONDS) // don't spam... + to_chat(usr, "[src]'s night lighting circuit breaker is still cycling!") + return 0 + last_nightshift_switch = world.time + nightshift_setting = params["nightshift"] + update_nightshift() + if("charge") + chargemode = !chargemode + if(!chargemode) + charging = 0 + update_icon() + if("channel") + if(params["eqp"]) + equipment = setsubsystem(text2num(params["eqp"])) + update_icon() + update() + else if(params["lgt"]) + lighting = setsubsystem(text2num(params["lgt"])) + update_icon() + update() + else if(params["env"]) + environ = setsubsystem(text2num(params["env"])) + update_icon() + update() + if("reboot") + failure_timer = 0 update_icon() - - else if (href_list["eqp"]) - var/val = text2num(href_list["eqp"]) - equipment = setsubsystem(val) - update_icon() - update() - - else if (href_list["lgt"]) - var/val = text2num(href_list["lgt"]) - lighting = setsubsystem(val) - update_icon() - update() - - else if (href_list["env"]) - var/val = text2num(href_list["env"]) - environ = setsubsystem(val) - update_icon() - update() - - else if (href_list["overload"]) - if(istype(usr, /mob/living/silicon)) - src.overload_lighting() - - else if (href_list["toggleaccess"]) - if(istype(usr, /mob/living/silicon)) - if(emagged || (stat & (BROKEN|MAINT))) - to_chat(usr, "The APC does not respond to the command.") - return - locked = !locked - update_icon() - - return 0 + update() + if("emergency_lighting") + emergency_lights = !emergency_lights + for(var/obj/machinery/light/L in area) + if(!initial(L.no_emergency)) //If there was an override set on creation, keep that override + L.no_emergency = emergency_lights + INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE) + CHECK_TICK + if("overload") + if(locked_exception) // Reusing for simplicity! + overload_lighting() /obj/machinery/power/apc/proc/toggle_breaker() operating = !operating - src.update() + update() update_icon() -//This isn't used for now, so might as well disable it -/* -/obj/machinery/power/apc/proc/ion_act() - if(prob(3)) - src.locked = 1 - if (src.cell.charge > 0) - src.cell.charge = 0 - cell.corrupt() - update_icon() - var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() - smoke.set_up(3, 0, src.loc) - smoke.attach(src) - smoke.start() - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - visible_message("The [src.name] suddenly lets out a blast of smoke and some sparks!", \ - "You hear sizzling electronics.") -*/ - /obj/machinery/power/apc/surplus() if(terminal) return terminal.surplus() @@ -1083,12 +1055,12 @@ GLOBAL_LIST_EMPTY(apcs) var/excess = surplus() - if(!src.avail()) - main_status = 0 + if(!avail()) + main_status = APC_EXTERNAL_POWER_NOTCONNECTED else if(excess < 0) - main_status = 1 + main_status = APC_EXTERNAL_POWER_NOENERGY else - main_status = 2 + main_status = APC_EXTERNAL_POWER_GOOD if(debug) log_debug("Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]") @@ -1122,7 +1094,7 @@ GLOBAL_LIST_EMPTY(apcs) // now trickle-charge the cell lastused_charging = 0 // Clear the variable for new use. - if(src.attempt_charging()) + if(attempt_charging()) if(excess > 0) // check to make sure we have enough to charge // Max charge is capped to % per second constant var/ch = min(excess*CELLRATE, cell.maxcharge*chargelevel) @@ -1170,7 +1142,7 @@ GLOBAL_LIST_EMPTY(apcs) force_update = 0 queue_icon_update() update() - else if (last_ch != charging) + else if(last_ch != charging) queue_icon_update() /obj/machinery/power/apc/proc/update_channels() @@ -1212,7 +1184,7 @@ GLOBAL_LIST_EMPTY(apcs) // val 0=off, 1=off(auto) 2=on 3=on(auto) // on 0=off, 1=on, 2=autooff // defines a state machine, returns the new state -obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) +/obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) switch(cur_state) //if(POWERCHAN_OFF); //autoset will never turn on a channel set to off if(POWERCHAN_OFF_AUTO) @@ -1253,24 +1225,24 @@ obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) switch(severity) if(1) //set_broken() //now qdel() do what we need - if (cell) + if(cell) cell.ex_act(1) // more lags woohoo qdel(src) return if(2) - if (prob(75)) + if(prob(75)) set_broken() - if (cell && prob(50)) + if(cell && prob(50)) cell.ex_act(2) if(3) - if (prob(50)) + if(prob(50)) set_broken() - if (cell && prob(50)) + if(cell && prob(50)) cell.ex_act(3) if(4) - if (prob(25)) + if(prob(25)) set_broken() - if (cell && prob(50)) + if(cell && prob(50)) cell.ex_act(3) return @@ -1282,7 +1254,7 @@ obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) /obj/machinery/power/apc/proc/set_broken() // Aesthetically much better! spawn(rand(2,5)) - src.visible_message("[src]'s screen flickers suddenly, then explodes in a rain of sparks and small debris!") + visible_message("[src]'s screen flickers suddenly, then explodes in a rain of sparks and small debris!") stat |= BROKEN operating = 0 update_icon() @@ -1314,7 +1286,7 @@ obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) /obj/machinery/power/apc/proc/ai_hack(var/mob/living/silicon/ai/A = null) if(!A || !A.hacked_apcs || hacker || aidisabled || A.stat == DEAD) return 0 - src.hacker = A + hacker = A A.hacked_apcs += src locked = 1 update_icon() @@ -1406,3 +1378,11 @@ obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) CHECK_TICK #undef APC_UPDATE_ICON_COOLDOWN + +#undef APC_EXTERNAL_POWER_NOTCONNECTED +#undef APC_EXTERNAL_POWER_NOENERGY +#undef APC_EXTERNAL_POWER_GOOD + +#undef APC_HAS_ELECTRONICS_NONE +#undef APC_HAS_ELECTRONICS_WIRED +#undef APC_HAS_ELECTRONICS_SECURED \ No newline at end of file diff --git a/code/modules/power/breaker_box.dm b/code/modules/power/breaker_box.dm index dc7cd0c519..5ebf482679 100644 --- a/code/modules/power/breaker_box.dm +++ b/code/modules/power/breaker_box.dm @@ -25,7 +25,7 @@ for(var/obj/structure/cable/C in src.loc) qdel(C) . = ..() - for(var/datum/nano_module/rcon/R in world) + for(var/datum/tgui_module/rcon/R in world) R.FindDevices() /obj/machinery/power/breakerbox/Initialize() diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm index 19ba3b8065..c6ad30ccc5 100644 --- a/code/modules/power/generator.dm +++ b/code/modules/power/generator.dm @@ -192,58 +192,48 @@ GLOBAL_LIST_EMPTY(all_turbines) if(stat & (BROKEN|NOPOWER) || !anchored) return if(!circ1 || !circ2) //Just incase the middle part of the TEG was not wrenched last. reconnect() - ui_interact(user) + tgui_interact(user) -/obj/machinery/power/generator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/power/generator/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TEGenerator", name) + ui.open() + +/obj/machinery/power/generator/tgui_data(mob/user) // this is the data which will be sent to the ui var/vertical = 0 if (dir == NORTH || dir == SOUTH) vertical = 1 - var/data[0] - data["totalOutput"] = effective_gen/1000 - data["maxTotalOutput"] = max_power/1000 - data["thermalOutput"] = last_thermal_gen/1000 - data["circConnected"] = 0 + var/list/data = list() + data["totalOutput"] = effective_gen + data["maxTotalOutput"] = max_power + data["thermalOutput"] = last_thermal_gen + data["primary"] = list() if(circ1) //The one on the left (or top) - data["primaryDir"] = vertical ? "top" : "left" - data["primaryOutput"] = last_circ1_gen/1000 - data["primaryFlowCapacity"] = circ1.volume_capacity_used*100 - data["primaryInletPressure"] = circ1.air1.return_pressure() - data["primaryInletTemperature"] = circ1.air1.temperature - data["primaryOutletPressure"] = circ1.air2.return_pressure() - data["primaryOutletTemperature"] = circ1.air2.temperature + data["primary"]["dir"] = vertical ? "top" : "left" + data["primary"]["output"] = last_circ1_gen + data["primary"]["flowCapacity"] = circ1.volume_capacity_used*100 + data["primary"]["inletPressure"] = circ1.air1.return_pressure() + data["primary"]["inletTemperature"] = circ1.air1.temperature + data["primary"]["outletPressure"] = circ1.air2.return_pressure() + data["primary"]["outletTemperature"] = circ1.air2.temperature + data["secondary"] = list() if(circ2) //Now for the one on the right (or bottom) - data["secondaryDir"] = vertical ? "bottom" : "right" - data["secondaryOutput"] = last_circ2_gen/1000 - data["secondaryFlowCapacity"] = circ2.volume_capacity_used*100 - data["secondaryInletPressure"] = circ2.air1.return_pressure() - data["secondaryInletTemperature"] = circ2.air1.temperature - data["secondaryOutletPressure"] = circ2.air2.return_pressure() - data["secondaryOutletTemperature"] = circ2.air2.temperature + data["secondary"]["dir"] = vertical ? "bottom" : "right" + data["secondary"]["output"] = last_circ2_gen + data["secondary"]["flowCapacity"] = circ2.volume_capacity_used*100 + data["secondary"]["inletPressure"] = circ2.air1.return_pressure() + data["secondary"]["inletTemperature"] = circ2.air1.temperature + data["secondary"]["outletPressure"] = circ2.air2.return_pressure() + data["secondary"]["outletTemperature"] = circ2.air2.temperature - if(circ1 && circ2) - data["circConnected"] = 1 - else - data["circConnected"] = 0 - - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "generator.tmpl", "Thermoelectric Generator", 450, 500) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + return data /obj/machinery/power/generator/power_change() ..() diff --git a/code/modules/power/gravitygenerator_vr.dm b/code/modules/power/gravitygenerator_vr.dm index 6e3d784fe4..3e4767a9a9 100644 --- a/code/modules/power/gravitygenerator_vr.dm +++ b/code/modules/power/gravitygenerator_vr.dm @@ -240,11 +240,16 @@ GLOBAL_LIST_EMPTY(gravity_generators) /obj/machinery/gravity_generator/main/attack_hand(mob/user) if((. = ..())) return - if(CanUseTopic(user, global.default_state) > STATUS_CLOSE) - ui_interact(user) - return TRUE + tgui_interact(user) + return TRUE -/obj/machinery/gravity_generator/main/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/gravity_generator/main/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GravityGenerator", name) + ui.open() + +/obj/machinery/gravity_generator/main/tgui_data(mob/user) var/data[0] data["breaker"] = breaker @@ -253,22 +258,18 @@ GLOBAL_LIST_EMPTY(gravity_generators) data["on"] = on data["operational"] = (stat & BROKEN) ? FALSE : TRUE - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "gravity_generator.tmpl", src.name, 500, 400) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/obj/machinery/gravity_generator/main/Topic(href, href_list, datum/topic_state/state = default_state) - if((. = ..())) - return +/obj/machinery/gravity_generator/main/tgui_act(action, params) + if((..())) + return TRUE - if(href_list["gentoggle"]) - breaker = !breaker - investigate_log("was toggled [breaker ? "ON" : "OFF"] by [key_name(usr)].", "gravity") - set_power() - return TOPIC_REFRESH + switch(action) + if("gentoggle") + breaker = !breaker + investigate_log("was toggled [breaker ? "ON" : "OFF"] by [key_name(usr)].", "gravity") + set_power() + return TOPIC_REFRESH // Power and Icon States diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 3251aee2f9..dce52720b4 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -7,6 +7,7 @@ density = 1 anchored = 0 use_power = USE_POWER_OFF + interact_offline = TRUE var/active = 0 var/power_gen = 5000 @@ -28,13 +29,22 @@ /obj/machinery/power/port_gen/proc/handleInactive() return +/obj/machinery/power/port_gen/proc/TogglePower() + if(active) + active = FALSE + icon_state = "[initial(icon_state)]" + // soundloop.stop() + else if(HasFuel()) + active = TRUE + icon_state = "[initial(icon_state)]on" + // soundloop.start() + /obj/machinery/power/port_gen/process() if(active && HasFuel() && !IsBroken() && anchored && powernet) add_avail(power_gen * power_output) UseFuel() - src.updateDialog() else - active = 0 + active = FALSE icon_state = initial(icon_state) handleInactive() @@ -121,7 +131,7 @@ return ..() /obj/machinery/power/port_gen/pacman/dismantle() - while ( sheets > 0 ) + while( sheets > 0 ) DropFuel() return ..() @@ -212,16 +222,16 @@ /obj/machinery/power/port_gen/pacman/handleInactive() var/cooling_temperature = 20 var/datum/gas_mixture/environment = loc.return_air() - if (environment) + if(environment) var/ratio = min(environment.return_pressure()/ONE_ATMOSPHERE, 1) var/ambient = environment.temperature - T20C cooling_temperature += ambient*ratio - if (temperature > cooling_temperature) + if(temperature > cooling_temperature) var/temp_loss = (temperature - cooling_temperature)/TEMPERATURE_DIVISOR temp_loss = between(2, round(temp_loss, 1), TEMPERATURE_CHANGE_MAX) temperature = max(temperature - temp_loss, cooling_temperature) - src.updateDialog() + updateDialog() if(overheating) overheating-- @@ -287,97 +297,77 @@ ..() if (!anchored) return - ui_interact(user) + tgui_interact(user) /obj/machinery/power/port_gen/pacman/attack_ai(mob/user as mob) - ui_interact(user) + tgui_interact(user) -/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/power/port_gen/tgui_status(mob/user, datum/tgui_state/state) if(IsBroken()) - return + return STATUS_CLOSE + return ..() + +/obj/machinery/power/port_gen/pacman/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortableGenerator", name) + ui.open() + +/obj/machinery/power/port_gen/pacman/tgui_data(mob/user) + var/list/data = list() - var/data[0] data["active"] = active + if(istype(user, /mob/living/silicon/ai)) - data["is_ai"] = 1 + data["is_ai"] = TRUE else if(istype(user, /mob/living/silicon/robot) && !Adjacent(user)) - data["is_ai"] = 1 + data["is_ai"] = TRUE else - data["is_ai"] = 0 - data["output_set"] = power_output - data["output_max"] = max_power_output - data["output_safe"] = max_safe_output - data["output_watts"] = power_output * power_gen - data["temperature_current"] = src.temperature - data["temperature_max"] = src.max_temperature - data["temperature_overheat"] = overheating - // 1 sheet = 1000cm3? + data["is_ai"] = FALSE + + data["sheet_name"] = capitalize(sheet_name) data["fuel_stored"] = round((sheets * 1000) + (sheet_left * 1000)) data["fuel_capacity"] = round(max_sheets * 1000, 0.1) data["fuel_usage"] = active ? round((power_output / time_per_sheet) * 1000) : 0 - data["fuel_type"] = sheet_name + data["anchored"] = anchored + data["connected"] = (powernet == null ? 0 : 1) + data["ready_to_boot"] = anchored && HasFuel() + data["power_generated"] = DisplayPower(power_gen) + data["power_output"] = DisplayPower(power_gen * power_output) + data["unsafe_output"] = power_output > max_safe_output + data["power_available"] = (powernet == null ? 0 : DisplayPower(avail())) + data["temperature_current"] = temperature + data["temperature_max"] = max_temperature + data["temperature_overheat"] = overheating + // 1 sheet = 1000cm3? + return data - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "pacman.tmpl", src.name, 500, 560) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - - -/* -/obj/machinery/power/port_gen/pacman/interact(mob/user) - if (get_dist(src, user) > 1 ) - if (!istype(user, /mob/living/silicon/ai)) - user.unset_machine() - user << browse(null, "window=port_gen" - return - - user.set_machine(src) - - var/dat = text("[name]
") - if (active) - dat += text("Generator: On
") - else - dat += text("Generator: Off
") - dat += text("[capitalize(sheet_name)]: [sheets] - Eject
") - var/stack_percent = round(sheet_left * 100, 1) - dat += text("Current stack: [stack_percent]%
") - dat += text("Power output: - [power_gen * power_output] Watts+
") - dat += text("Power current: [(powernet == null ? "Unconnected" : "[avail()]")]
") - - var/tempstr = "Temperature: [temperature]°C
" - dat += (overheating)? "[tempstr]" : tempstr - dat += "
Close" - user << browse("[dat]", "window=port_gen") - onclose(user, "port_gen") -*/ - -/obj/machinery/power/port_gen/pacman/Topic(href, href_list) +/obj/machinery/power/port_gen/pacman/tgui_act(action, params) if(..()) return - src.add_fingerprint(usr) - if(href_list["action"]) - if(href_list["action"] == "enable") - if(!active && HasFuel() && !IsBroken()) - active = 1 - icon_state = "[initial(icon_state)]on" //VOREStation Edit - if(href_list["action"] == "disable") - if (active) - active = 0 - icon_state = initial(icon_state) //VOREStation Edit - if(href_list["action"] == "eject") + add_fingerprint(usr) + switch(action) + if("toggle_power") + TogglePower() + . = TRUE + + if("eject") if(!active) DropFuel() - if(href_list["action"] == "lower_power") - if (power_output > 1) + . = TRUE + + if("lower_power") + if(power_output > 1) power_output-- - if (href_list["action"] == "higher_power") - if (power_output < max_power_output || (emagged && power_output < round(max_power_output*2.5))) + . = TRUE + + if("higher_power") + if(power_output < max_power_output || (emagged && power_output < round(max_power_output * 2.5))) power_output++ + . = TRUE /obj/machinery/power/port_gen/pacman/super name = "S.U.P.E.R.P.A.C.M.A.N.-type Portable Generator" diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm index b08586a449..1747842df9 100644 --- a/code/modules/power/powernet.dm +++ b/code/modules/power/powernet.dm @@ -5,6 +5,7 @@ var/load = 0 // the current load on the powernet, increased by each machine at processing var/newavail = 0 // what available power was gathered last tick, then becomes... var/avail = 0 //...the current available power in the powernet + var/viewavail = 0 // the availability as it appears on the power console (gradually updated) var/viewload = 0 // the load as it appears on the power console (gradually updated) var/number = 0 // Unused //TODEL @@ -134,7 +135,8 @@ S.restore(perc) //updates the viewed load (as seen on power computers) - viewload = round(load) + viewavail = round(0.8 * viewavail + 0.2 * avail) + viewload = round(0.8 * viewload + 0.2 * load) //reset the powernet load = 0 diff --git a/code/modules/power/sensors/powernet_sensor.dm b/code/modules/power/sensors/powernet_sensor.dm index bc1298d201..6f1b53db05 100644 --- a/code/modules/power/sensors/powernet_sensor.dm +++ b/code/modules/power/sensors/powernet_sensor.dm @@ -19,12 +19,22 @@ var/name_tag = "#UNKN#" // ID tag displayed in list of powernet sensors. Each sensor should have it's own tag! var/long_range = 0 // If 1, sensor reading will show on all computers, regardless of Zlevel + var/list/history = list() + var/record_size = 60 + var/record_interval = 50 + var/next_record = 0 + var/is_secret_monitor = FALSE + // Proc: New() // Parameters: None // Description: Automatically assigns name according to ID tag. /obj/machinery/power/sensor/New() ..() auto_set_name() +/obj/machinery/power/sensor/Initialize() + . = ..() + history["supply"] = list() + history["demand"] = list() // Proc: auto_set_name() // Parameters: None @@ -38,6 +48,8 @@ for(var/obj/machinery/computer/power_monitor/PM in machines) if(PM.power_monitor) PM.power_monitor.refresh_sensors() + history.Cut() + history = null // Proc: check_grid_warning() // Parameters: None @@ -51,10 +63,67 @@ // Proc: process() // Parameters: None -// Description: This has to be here because we need sensors to remain in Machines list. +// Description: This tracks historical usage, for TGUI power monitors /obj/machinery/power/sensor/process() + if(!powernet) + use_power = USE_POWER_IDLE + connect_to_network() + else + use_power = USE_POWER_ACTIVE + record() return 1 +// This tracks historical usage, for TGUI power monitors +/obj/machinery/power/sensor/proc/record() + if(world.time >= next_record) + next_record = world.time + record_interval + + var/datum/powernet/connected_powernet = powernet + + var/list/supply = history["supply"] + if(connected_powernet) + supply += connected_powernet.viewavail + if(supply.len > record_size) + supply.Cut(1, 2) + + var/list/demand = history["demand"] + if(connected_powernet) + demand += connected_powernet.viewload + if(demand.len > record_size) + demand.Cut(1, 2) + +/obj/machinery/power/sensor/tgui_data() + var/list/data = list() + + data["name"] = name_tag + data["stored"] = record_size + data["interval"] = record_interval / 10 + data["attached"] = !!powernet + data["history"] = history + + data["areas"] = list() + if(powernet) + for(var/obj/machinery/power/terminal/term in powernet.nodes) + if(istype(term.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = term.master + if(istype(A)) + var/cell_charge + if(!A.cell) + cell_charge = 0 + else + cell_charge = A.cell.percent() + data["areas"] += list(list( + "name" = A.area.name, + "charge" = cell_charge, + "load" = DisplayPower(A.lastused_total), + "charging" = A.charging, + "eqp" = A.equipment, + "lgt" = A.lighting, + "env" = A.environ, + )) + + return data + // Proc: reading_to_text() // Parameters: 1 (amount - Power in Watts to be converted to W, kW or MW) // Description: Helper proc that converts reading in Watts to kW or MW (returns string version of amount parameter) @@ -178,7 +247,7 @@ APC_entry["total_load"] = reading_to_text(A.lastused_total) // Hopefully removes those goddamn \improper s which are screwing up the UI var/N = A.area.name - if(findtext(N, "ÿ")) + if(findtext(N, "�")) N = copytext(N, 3) APC_entry["name"] = N // Add data into main list of APC data. diff --git a/code/modules/power/sensors/sensor_monitoring.dm b/code/modules/power/sensors/sensor_monitoring.dm index e243b7f75b..4e6198f410 100644 --- a/code/modules/power/sensors/sensor_monitoring.dm +++ b/code/modules/power/sensors/sensor_monitoring.dm @@ -18,7 +18,7 @@ use_power = USE_POWER_IDLE idle_power_usage = 300 active_power_usage = 300 - var/datum/nano_module/power_monitor/power_monitor + var/datum/tgui_module/power_monitor/power_monitor // Checks the sensors for alerts. If change (alerts cleared or detected) occurs, calls for icon update. /obj/machinery/computer/power_monitor/process() @@ -47,12 +47,11 @@ if(stat & (BROKEN|NOPOWER)) return - ui_interact(user) + tgui_interact(user) // Uses dark magic to operate the NanoUI of this computer. -/obj/machinery/computer/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - power_monitor.ui_interact(user, ui_key, ui, force_open) - +/obj/machinery/computer/power_monitor/tgui_interact(mob/user, var/datum/tgui/ui = null) + power_monitor.tgui_interact(user, ui) // Verifies if any warnings were registered by connected sensors. /obj/machinery/computer/power_monitor/proc/check_warnings() diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index bcb72061f4..6beda2db15 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -36,7 +36,7 @@ /obj/machinery/particle_accelerator/control_box/attack_hand(mob/user as mob) if(construction_state >= 3) - interact(user) + tgui_interact(user) else if(construction_state == 2) // Wires exposed wires.Interact(user) @@ -77,36 +77,6 @@ else icon_state = "[reference]c" -/obj/machinery/particle_accelerator/control_box/Topic(href, href_list) - ..() - //Ignore input if we are broken, !silicon guy cant touch us, or nonai controlling from super far away - if(stat & (BROKEN|NOPOWER) || (get_dist(src, usr) > 1 && !istype(usr, /mob/living/silicon)) || (get_dist(src, usr) > 8 && !istype(usr, /mob/living/silicon/ai))) - usr.unset_machine() - usr << browse(null, "window=pacontrol") - return - - if( href_list["close"] ) - usr << browse(null, "window=pacontrol") - usr.unset_machine() - return - - if(href_list["togglep"]) - if(!wires.is_cut(WIRE_PARTICLE_POWER)) - toggle_power() - else if(href_list["scan"]) - part_scan() - - else if(href_list["strengthup"]) - if(!wires.is_cut(WIRE_PARTICLE_STRENGTH)) - add_strength() - - else if(href_list["strengthdown"]) - if(!wires.is_cut(WIRE_PARTICLE_STRENGTH)) - remove_strength() - - updateDialog() - update_icon() - /obj/machinery/particle_accelerator/control_box/proc/strength_change() for(var/obj/structure/particle_accelerator/part in connected_parts) part.strength = strength @@ -230,33 +200,54 @@ part.update_icon() return 1 +/obj/machinery/particle_accelerator/control_box/proc/is_interactive(mob/user) + if(!interface_control) + to_chat(user, "ERROR: Request timed out. Check wire contacts.") + return FALSE + if(construction_state != 3) + return FALSE + return TRUE -/obj/machinery/particle_accelerator/control_box/interact(mob/user) - if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER))) - if(!istype(user, /mob/living/silicon)) - user.unset_machine() - user << browse(null, "window=pacontrol") - return - user.set_machine(src) +/obj/machinery/particle_accelerator/control_box/tgui_status(mob/user) + if(is_interactive(user)) + return ..() + return STATUS_CLOSE - var/dat = "" - dat += "Particle Accelerator Control Panel
" - dat += "Close

" - dat += "Status:
" - if(!assembled) - dat += "Unable to detect all parts!
" - dat += "Run Scan

" - else - dat += "All parts in place.

" - dat += "Power:" - if(active) - dat += "On
" - else - dat += "Off
" - dat += "Toggle Power

" - dat += "Particle Strength: [src.strength] " - dat += "--|++

" +/obj/machinery/particle_accelerator/control_box/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ParticleAccelerator", name) + ui.open() - user << browse(dat, "window=pacontrol;size=420x500") - onclose(user, "pacontrol") - return +/obj/machinery/particle_accelerator/control_box/tgui_data(mob/user) + var/list/data = list() + data["assembled"] = assembled + data["power"] = active + data["strength"] = strength + return data + +/obj/machinery/particle_accelerator/control_box/tgui_act(action, params) + if(..()) + return + + switch(action) + if("power") + if(wires.is_cut(WIRE_POWER)) + return + toggle_power() + . = TRUE + if("scan") + part_scan() + . = TRUE + if("add_strength") + if(wires.is_cut(WIRE_PARTICLE_STRENGTH)) + return + add_strength() + . = TRUE + if("remove_strength") + if(wires.is_cut(WIRE_PARTICLE_STRENGTH)) + return + remove_strength() + . = TRUE + + update_icon() diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index c05c4e1523..365fda6b50 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -263,11 +263,11 @@ GLOBAL_LIST_EMPTY(smeses) /obj/machinery/power/smes/attack_ai(mob/user) add_hiddenprint(user) - ui_interact(user) + tgui_interact(user) /obj/machinery/power/smes/attack_hand(mob/user) add_fingerprint(user) - ui_interact(user) + tgui_interact(user) /obj/machinery/power/smes/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) @@ -344,78 +344,84 @@ GLOBAL_LIST_EMPTY(smeses) return FALSE return TRUE -/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - - if(stat & BROKEN) - return - - // this is the data which will be sent to the ui - var/data[0] - data["nameTag"] = name_tag - data["storedCapacity"] = round(100.0*charge/capacity, 0.1) - data["storedCapacityAbs"] = round(charge/(1000*60), 0.1) - data["storedCapacityMax"] = round(capacity/(1000*60)) - data["charging"] = inputting - data["chargeMode"] = input_attempt - data["chargeLevel"] = round(input_level/1000, 0.1) - data["chargeMax"] = round(input_level_max/1000) - data["chargeLoad"] = round(input_available/1000, 0.1) - data["outputOnline"] = output_attempt - data["outputLevel"] = round(output_level/1000, 0.1) - data["outputMax"] = round(output_level_max/1000) - data["outputLoad"] = round(output_used/1000, 0.1) - data["outputting"] = outputting - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "smes.tmpl", "SMES Unit", 540, 380) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window +/obj/machinery/power/smes/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Smes", name) ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + +/obj/machinery/power/smes/tgui_data() + var/list/data = list( + "capacity" = capacity, + "capacityPercent" = round(100*charge/capacity, 0.1), + "charge" = charge, + "inputAttempt" = input_attempt, + "inputting" = inputting, + "inputLevel" = input_level, + "inputLevel_text" = DisplayPower(input_level), + "inputLevelMax" = input_level_max, + "inputAvailable" = input_available, + "outputAttempt" = output_attempt, + "outputting" = outputting, + "outputLevel" = output_level, + "outputLevel_text" = DisplayPower(output_level), + "outputLevelMax" = output_level_max, + "outputUsed" = output_used, + ) + return data /obj/machinery/power/smes/proc/Percentage() if(!capacity) return 0 return round(100.0*charge/capacity, 0.1) -/obj/machinery/power/smes/Topic(href, href_list) - if(..()) - return 1 - if( href_list["cmode"] ) - inputting(!input_attempt) - update_icon() - return 1 - else if( href_list["online"] ) - outputting(!output_attempt) - update_icon() - return 1 - else if( href_list["input"] ) - switch( href_list["input"] ) - if("min") - input_level = 0 - if("max") - input_level = input_level_max - if("set") - input_level = (input(usr, "Enter new input level (0-[input_level_max/1000] kW)", "SMES Input Power Control", input_level/1000) as num) * 1000 - input_level = max(0, min(input_level_max, input_level)) // clamp to range - return 1 - else if( href_list["output"] ) - switch( href_list["output"] ) - if("min") - output_level = 0 - if("max") - output_level = output_level_max - if("set") - output_level = (input(usr, "Enter new output level (0-[output_level_max/1000] kW)", "SMES Output Power Control", output_level/1000) as num) * 1000 - output_level = max(0, min(output_level_max, output_level)) // clamp to range - return 1 +/obj/machinery/power/smes/tgui_act(action, params) + if(..()) + return TRUE + switch(action) + if("tryinput") + inputting(!input_attempt) + update_icon() + . = TRUE + if("tryoutput") + outputting(!output_attempt) + update_icon() + . = TRUE + if("input") + var/target = params["target"] + var/adjust = text2num(params["adjust"]) + if(target == "min") + target = 0 + . = TRUE + else if(target == "max") + target = input_level_max + . = TRUE + else if(adjust) + target = input_level + adjust + . = TRUE + else if(text2num(target) != null) + target = text2num(target) + . = TRUE + if(.) + input_level = clamp(target, 0, input_level_max) + if("output") + var/target = params["target"] + var/adjust = text2num(params["adjust"]) + if(target == "min") + target = 0 + . = TRUE + else if(target == "max") + target = output_level_max + . = TRUE + else if(adjust) + target = output_level + adjust + . = TRUE + else if(text2num(target) != null) + target = text2num(target) + . = TRUE + if(.) + output_level = clamp(target, 0, output_level_max) /obj/machinery/power/smes/proc/inputting(var/do_input) input_attempt = do_input diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm index f8bf16087e..45b44d64f8 100644 --- a/code/modules/power/smes_construction.dm +++ b/code/modules/power/smes_construction.dm @@ -84,7 +84,7 @@ /obj/machinery/power/smes/buildable/Destroy() qdel(wires) wires = null - for(var/datum/nano_module/rcon/R in world) + for(var/datum/tgui_module/rcon/R in world) R.FindDevices() return ..() diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 27f1953b32..850bb5807c 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -399,38 +399,32 @@ GLOBAL_LIST_EMPTY(solars_list) return /obj/machinery/power/solar_control/attack_hand(mob/user) - if(!..()) - interact(user) + if(..()) + return TRUE + tgui_interact(user) -/obj/machinery/power/solar_control/interact(mob/user) +/obj/machinery/power/solar_control/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SolarControl", name) + ui.open() - var/t = "Generated power : [round(lastgen)] W
" - t += "Star Orientation: [SSsun.sun.angle]° ([angle2text(SSsun.sun.angle)])
" - t += "Array Orientation: [rate_control(src,"cdir","[cdir]°",1,15)] ([angle2text(cdir)])
" - t += "Tracking:
" - switch(track) - if(0) - t += "Off Timed Auto
" - if(1) - t += "Off Timed Auto
" - if(2) - t += "Off Timed Auto
" +/obj/machinery/power/solar_control/tgui_data() + var/data = list() - t += "Tracking Rate: [rate_control(src,"tdir","[trackrate] deg/h ([trackrate<0 ? "CCW" : "CW"])",1,30,180)]

" + data["generated"] = round(lastgen) + data["generated_ratio"] = data["generated"] / round(max(connected_panels.len, 1) * GLOB.solar_gen_rate) - t += "Connected devices:
" + data["sun_angle"] = SSsun.sun.angle + data["array_angle"] = cdir + data["rotation_rate"] = trackrate + data["max_rotation_rate"] = 7200 + data["tracking_state"] = track - t += "Search for devices
" - t += "Solar panels : [connected_panels.len] connected
" - t += "Solar tracker : [connected_tracker ? "Found" : "Not found"]

" + data["connected_panels"] = connected_panels.len + data["connected_tracker"] = (connected_tracker ? TRUE : FALSE) - t += "Close" - - var/datum/browser/popup = new(user, "solar", name) - popup.set_content(t) - popup.open() - - return + return data /obj/machinery/power/solar_control/attackby(obj/item/I, user as mob) if(I.is_screwdriver()) @@ -481,51 +475,52 @@ GLOBAL_LIST_EMPTY(solars_list) updateDialog() -/obj/machinery/power/solar_control/Topic(href, href_list) +/obj/machinery/power/solar_control/tgui_act(action, params) if(..()) - usr << browse(null, "window=solcon") - usr.unset_machine() - return 0 - if(href_list["close"] ) - usr << browse(null, "window=solcon") - usr.unset_machine() - return 0 + return TRUE - if(href_list["rate control"]) - if(href_list["cdir"]) - src.cdir = dd_range(0,359,(360+src.cdir+text2num(href_list["cdir"]))%360) - src.targetdir = src.cdir - if(track == 2) //manual update, so losing auto-tracking - track = 0 - spawn(1) + switch(action) + if("azimuth") + var/adjust = text2num(params["adjust"]) + var/value = text2num(params["value"]) + if(adjust) + value = cdir + adjust + if(value != null) + cdir = value set_panels(cdir) - if(href_list["tdir"]) - src.trackrate = dd_range(-7200,7200,src.trackrate+text2num(href_list["tdir"])) - if(src.trackrate) nexttime = world.time + 36000/abs(trackrate) + return TRUE + return FALSE + if("azimuth_rate") + var/adjust = text2num(params["adjust"]) + var/value = text2num(params["value"]) + if(adjust) + value = trackrate + adjust + if(value != null) + trackrate = round(clamp(value, -7200, 7200), 0.01) + if(trackrate) + nexttime = world.time + 36000 / abs(trackrate) + return TRUE + return TRUE + if("tracking") + var/mode = text2num(params["mode"]) + track = mode + if(track == 2) + if(connected_tracker) + connected_tracker.set_angle(SSsun.sun.angle) + set_panels(cdir) + else if(track == 1) //begin manual tracking + targetdir = cdir + if(trackrate) + nexttime = world.time + 36000/abs(trackrate) + set_panels(targetdir) + return TRUE - if(href_list["track"]) - track = text2num(href_list["track"]) - if(track == 2) - if(connected_tracker) - connected_tracker.set_angle(SSsun.sun.angle) - set_panels(cdir) - else if (track == 1) //begin manual tracking - src.targetdir = src.cdir - if(src.trackrate) nexttime = world.time + 36000/abs(trackrate) - set_panels(targetdir) - - if(href_list["search_connected"]) - src.search_for_connected() - if(connected_tracker && track == 2) - connected_tracker.set_angle(SSsun.sun.angle) - src.set_panels(cdir) - - interact(usr) - return 1 + if("refresh") + search_for_connected() + return TRUE //rotates the panel to the passed angle /obj/machinery/power/solar_control/proc/set_panels(var/cdir) - for(var/obj/machinery/power/solar/S in connected_panels) S.adir = cdir //instantly rotates the panel S.occlusion()//and @@ -547,7 +542,7 @@ GLOBAL_LIST_EMPTY(solars_list) /obj/machinery/power/solar_control/ex_act(severity) switch(severity) if(1.0) - //SN src = null + //SN = null qdel(src) return if(2.0) @@ -565,9 +560,3 @@ GLOBAL_LIST_EMPTY(solars_list) /obj/item/weapon/paper/solar name = "paper- 'Going green! Setup your own solar array instructions.'" info = "

Welcome

At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuel or phoron! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array.

You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!

Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the SSsun.sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the SSsun.sun's movements and to send commands to the solar panels to change direction with the SSsun.sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker.

Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.

That's all to it, be safe, be green!

" - -/proc/rate_control(var/S, var/V, var/C, var/Min=1, var/Max=5, var/Limit=null) //How not to name vars - var/href = "-[href]=-[Min]'>- [(C?C : 0)] [href]=[Min]'>+[href]=[Max]'>+" - if(Limit) return "[href]=-[Limit]'>-"+rate+"[href]=[Limit]'>+" - return rate diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 3d651a2a0f..4e6c5a6cb5 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -390,11 +390,11 @@ if(Adjacent(user)) return attack_hand(user) else - ui_interact(user) + tgui_interact(user) return /obj/machinery/power/supermatter/attack_ai(mob/user as mob) - ui_interact(user) + tgui_interact(user) /obj/machinery/power/supermatter/attack_hand(mob/user as mob) var/datum/gender/TU = gender_datums[user.get_visible_gender()] @@ -404,9 +404,15 @@ Consume(user) +/obj/machinery/power/supermatter/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AiSupermatter", name) + ui.open() + // This is purely informational UI that may be accessed by AIs or robots -/obj/machinery/power/supermatter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/power/supermatter/tgui_data(mob/user) + var/list/data = list() data["integrity_percentage"] = round(get_integrity()) var/datum/gas_mixture/env = null @@ -421,12 +427,7 @@ data["ambient_pressure"] = round(env.return_pressure()) data["detonating"] = grav_pulling - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "supermatter_crystal.tmpl", "Supermatter Crystal", 500, 300) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data /obj/machinery/power/supermatter/attackby(obj/item/weapon/W as obj, mob/living/user as mob) diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 97c81cf7cb..6e4c2e4dd2 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -7,6 +7,7 @@ #define MAX_MULTI_AMOUNT 20 // Max number of pills/patches that can be made at once #define MAX_UNITS_PER_PILL 60 // Max amount of units in a pill #define MAX_UNITS_PER_PATCH 60 // Max amount of units in a patch +#define MAX_UNITS_PER_BOTTLE 60 // Max amount of units in a bottle (it's volume) #define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever @@ -245,7 +246,18 @@ if("create_bottle") if(condi || !reagents.total_volume) return - tgui_modal_input(src, id, "Please name your bottle:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN) + var/num = round(text2num(arguments["num"] || 1)) + if(!num) + return + arguments["num"] = num + var/amount_per_bottle = CLAMP(reagents.total_volume / num, 0, MAX_UNITS_PER_BOTTLE) + var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_bottle]u)" + var/bottles_text = num == 1 ? "new bottle" : "[num] new bottles" + tgui_modal_input(src, id, "Please name your [bottles_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN) + if("create_bottle_multiple") + if(condi || !reagents.total_volume) + return + tgui_modal_input(src, id, "Please enter the amount of bottles to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5) if("change_bottle_style") var/list/choices = list() for(var/i = 1 to MAX_BOTTLE_SPRITE) @@ -357,16 +369,28 @@ if("create_bottle") if(condi || !reagents.total_volume) return + var/count = CLAMP(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT) + if(!count) + return if(!length(answer)) answer = reagents.get_master_reagent_name() - var/obj/item/weapon/reagent_containers/glass/bottle/P = new(loc) - P.name = "[answer] bottle" - P.pixel_x = rand(-7, 7) // random position - P.pixel_y = rand(-7, 7) - P.icon_state = "bottle-[bottlesprite]" || "bottle-1" - reagents.trans_to_obj(P, 60) - P.update_icon() + var/amount_per_bottle = CLAMP(reagents.total_volume / count, 0, MAX_UNITS_PER_BOTTLE) + while(count--) + if(reagents.total_volume <= 0) + to_chat(usr, "Not enough reagents to create these bottles!") + return + var/obj/item/weapon/reagent_containers/glass/bottle/P = new(loc) + P.name = "[answer] bottle" + P.pixel_x = rand(-7, 7) // random position + P.pixel_y = rand(-7, 7) + P.icon_state = "bottle-[bottlesprite]" || "bottle-1" + reagents.trans_to_obj(P, amount_per_bottle) + P.update_icon() + if("create_bottle_multiple") + if(condi || !reagents.total_volume) + return + tgui_act("modal_open", list("id" = "create_bottle", "arguments" = list("num" = answer)), ui, state) if("change_bottle_style") var/new_style = CLAMP(text2num(answer) || 0, 0, MAX_BOTTLE_SPRITE) if(!new_style) @@ -393,7 +417,9 @@ mode = !mode if("ejectp") if(loaded_pill_bottle) - loaded_pill_bottle.forceMove(loc) + loaded_pill_bottle.forceMove(get_turf(src)) + if(Adjacent(usr) && !issilicon(usr)) + usr.put_in_hands(loaded_pill_bottle) loaded_pill_bottle = null if("print") if(printing || condi) @@ -842,4 +868,5 @@ #undef MAX_MULTI_AMOUNT #undef MAX_UNITS_PER_PILL #undef MAX_UNITS_PER_PATCH +#undef MAX_UNITS_PER_BOTTLE #undef MAX_CUSTOM_NAME_LEN diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm index 353df9095c..681929691a 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm @@ -400,6 +400,49 @@ M.heal_organ_damage(30 * removed, 30 * removed * chem_effective) M.adjustToxLoss(-30 * removed * chem_effective) +/datum/reagent/mortiferin + name = "Mortiferin" + id = "mortiferin" + description = "A liquid compound based upon those used in cloning. Utilized in cases of toxic shock. May cause liver damage." + taste_description = "meat" + reagent_state = LIQUID + color = "#6b4de3" + metabolism = REM * 0.5 + mrate_static = TRUE + scannable = 1 + +/datum/reagent/mortiferin/on_mob_life(var/mob/living/carbon/M, var/alien, var/datum/reagents/metabolism/location) + if(M.stat == DEAD && M.has_modifier_of_type(/datum/modifier/bloodpump_corpse)) + affects_dead = TRUE + else + affects_dead = FALSE + + . = ..(M, alien, location) + +/datum/reagent/mortiferin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(M.bodytemperature < (T0C - 10) || (M.stat == DEAD && M.has_modifier_of_type(/datum/modifier/bloodpump_corpse))) + var/chem_effective = 1 * M.species.chem_strength_heal + if(alien == IS_SLIME) + if(prob(10)) + to_chat(M, "It's so cold. Something causes your cellular mass to solidify sporadically, resulting in uncontrollable twitching.") + chem_effective = 0.5 + M.Weaken(10) + M.silent = max(M.silent, 10) + M.make_jittery(4) + if(M.stat != DEAD) + M.adjustCloneLoss(-5 * removed * chem_effective) + M.adjustOxyLoss(-10 * removed * chem_effective) + M.adjustToxLoss(-20 * removed * chem_effective) + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/liver/L = H.internal_organs_by_name[O_LIVER] + if(istype(L) && prob(5)) + if(L.robotic >= ORGAN_ROBOT) + return + + L.take_damage(rand(1,3) * removed) + /datum/reagent/necroxadone name = "Necroxadone" id = "necroxadone" @@ -410,18 +453,11 @@ metabolism = REM * 0.5 mrate_static = TRUE scannable = 1 - -/datum/reagent/necroxadone/on_mob_life(var/mob/living/carbon/M, var/alien, var/datum/reagents/metabolism/location) - if(M.stat == DEAD && M.has_modifier_of_type(/datum/modifier/bloodpump_corpse)) - affects_dead = TRUE - else - affects_dead = FALSE - - . = ..(M, alien, location) + affects_dead = TRUE /datum/reagent/necroxadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + var/chem_effective = 1 * M.species.chem_strength_heal if(M.bodytemperature < 170 || (M.stat == DEAD && M.has_modifier_of_type(/datum/modifier/bloodpump_corpse))) - var/chem_effective = 1 * M.species.chem_strength_heal if(alien == IS_SLIME) if(prob(10)) to_chat(M, "It's so cold. Something causes your cellular mass to harden sporadically, resulting in seizure-like twitching.") @@ -433,6 +469,12 @@ M.adjustCloneLoss(-5 * removed * chem_effective) M.adjustOxyLoss(-20 * removed * chem_effective) M.adjustToxLoss(-40 * removed * chem_effective) + M.adjustCloneLoss(-15 * removed * chem_effective) + + else + M.adjustToxLoss(-25 * removed * chem_effective) + M.adjustOxyLoss(-10 * removed * chem_effective) + M.adjustCloneLoss(-7 * removed * chem_effective) /* Painkillers */ diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index f5f4d17587..9adb2558b9 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -428,6 +428,14 @@ catalysts = list("phoron" = 5) result_amount = 2 +/datum/chemical_reaction/mortiferin + name = "Mortiferin" + id = "mortiferin" + result = "mortiferin" + required_reagents = list("cryptobiolin" = 1, "clonexadone" = 1, "corophizine" = 1) + result_amount = 2 + catalysts = list("phoron" = 5) + /datum/chemical_reaction/spaceacillin name = "Spaceacillin" id = "spaceacillin" diff --git a/code/modules/research/mechfab_designs.dm b/code/modules/research/mechfab_designs.dm index 899b5fd9db..a5031055c3 100644 --- a/code/modules/research/mechfab_designs.dm +++ b/code/modules/research/mechfab_designs.dm @@ -569,9 +569,9 @@ materials = list(DEFAULT_WALL_MATERIAL = 7500, "gold" = 750, "silver" = 1500, "glass" = 3750) build_path = /obj/item/mecha_parts/mecha_equipment/repair_droid -/datum/design/item/mecha/shield_drone - name = "Shield Drone" - desc = "Manual shield drone. Deploys a large, familiar, and rectangular shield in one direction at a time." +/datum/design/item/mecha/combat_shield + name = "linear combat shield" + desc = "Linear shield projector. Deploys a large, familiar, and rectangular shield in one direction at a time." id = "mech_shield_droid" req_tech = list(TECH_PHORON = 3, TECH_MAGNET = 6, TECH_ILLEGAL = 4) materials = list(DEFAULT_WALL_MATERIAL = 8000, "gold" = 2000, "silver" = 3000, "phoron" = 5000, "glass" = 3750) diff --git a/code/modules/resleeving/designer.dm b/code/modules/resleeving/designer.dm index 3e2aa57aab..c09aec2aac 100644 --- a/code/modules/resleeving/designer.dm +++ b/code/modules/resleeving/designer.dm @@ -1,6 +1,12 @@ // Little define makes it cleaner to read the tripple color values out of mobs. #define MOB_HEX_COLOR(M, V) "#[num2hex(M.r_##V, 2)][num2hex(M.g_##V, 2)][num2hex(M.b_##V, 2)]" +#define MENU_MAIN "Main" +#define MENU_BODYRECORDS "Body Records" +#define MENU_STOCKRECORDS "Stock Records" +#define MENU_SPECIFICRECORD "Specific Record" +#define MENU_OOCNOTES "OOC Notes" + /obj/machinery/computer/transhuman/designer name = "body design console" catalogue_data = list(/datum/category_item/catalogue/information/organization/khi, @@ -12,16 +18,41 @@ circuit = /obj/item/weapon/circuitboard/body_designer req_access = list(access_medical) // Used for loading people's designs var/temp = "" - var/menu = 1 //Which menu screen to display + var/menu = MENU_MAIN //Which menu screen to display var/datum/transhuman/body_record/active_br = null - var/icon/preview_icon = null + //Mob preview + var/map_name + var/obj/screen/south_preview = null + var/obj/screen/east_preview = null + var/obj/screen/west_preview = null // Mannequins are somewhat expensive to create, so cache it var/mob/living/carbon/human/dummy/mannequin/mannequin = null var/obj/item/weapon/disk/body_record/disk = null +/obj/machinery/computer/transhuman/designer/Initialize() + . = ..() + map_name = "transhuman_designer_[REF(src)]_map" + + south_preview = new + south_preview.name = "" + south_preview.assigned_map = map_name + south_preview.del_on_map_removal = FALSE + south_preview.screen_loc = "[map_name]:1,1" + + east_preview = new + east_preview.name = "" + east_preview.assigned_map = map_name + east_preview.del_on_map_removal = FALSE + east_preview.screen_loc = "[map_name]:2,1" + + west_preview = new + west_preview.name = "" + west_preview.assigned_map = map_name + west_preview.del_on_map_removal = FALSE + west_preview.screen_loc = "[map_name]:0,1" + /obj/machinery/computer/transhuman/designer/Destroy() active_br = null - preview_icon = null mannequin = null disk = null return ..() @@ -50,15 +81,24 @@ add_fingerprint(user) if(inoperable()) return - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/transhuman/designer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - // log_debug("designer.ui_interact([user], force_open = [force_open])") - user.set_machine(src) +/obj/machinery/computer/transhuman/designer/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + give_client_previews(user.client) + ui = new(user, src, "BodyDesigner", name) + ui.open() - var/data[0] +/obj/machinery/computer/transhuman/designer/tgui_static_data(mob/user) + var/list/data = ..() + data["mapRef"] = map_name + return data - if(menu == "2") +/obj/machinery/computer/transhuman/designer/tgui_data(mob/user) + var/list/data = list() + + if(menu == MENU_BODYRECORDS) var/bodyrecords_list_ui[0] for(var/N in SStranscore.body_scans) var/datum/transhuman/body_record/BR = SStranscore.body_scans[N] @@ -66,7 +106,7 @@ if(bodyrecords_list_ui.len) data["bodyrecords"] = bodyrecords_list_ui - if(menu == "3") + if(menu == MENU_STOCKRECORDS) var/stock_bodyrecords_list_ui[0] for (var/N in GLOB.all_species) var/datum/species/S = GLOB.all_species[N] @@ -86,11 +126,6 @@ "booc" = active_br.body_oocnotes, "styles" = list() ) - if(!preview_icon) - update_preview_icon() - force_open = 1 // Force a refresh to send the new image - data["previewIconUrl"] = "body_preview_icon.png" - user << browse_rsc(preview_icon, "body_preview_icon.png") var/list/styles = data["activeBodyRecord"]["styles"] var/list/temp @@ -98,6 +133,12 @@ temp = list("styleHref" = "ear_style", "style" = "Normal") if(mannequin.ear_style) temp["style"] = mannequin.ear_style.name + if(mannequin.ear_style.do_colouration) + temp["color"] = MOB_HEX_COLOR(mannequin, ears) + temp["colorHref"] = "ear_color" + if(mannequin.ear_style.extra_overlay) + temp["color2"] = MOB_HEX_COLOR(mannequin, ears2) + temp["colorHref2"] = "ear_color2" styles["Ears"] = temp temp = list("styleHref" = "tail_style", "style" = "Normal") @@ -106,6 +147,9 @@ if(mannequin.tail_style.do_colouration) temp["color"] = MOB_HEX_COLOR(mannequin, tail) temp["colorHref"] = "tail_color" + if(mannequin.tail_style.extra_overlay) + temp["color2"] = MOB_HEX_COLOR(mannequin, tail2) + temp["colorHref2"] = "tail_color2" styles["Tail"] = temp temp = list("styleHref" = "wing_style", "style" = "Normal") @@ -114,6 +158,9 @@ if(mannequin.wing_style.do_colouration) temp["color"] = MOB_HEX_COLOR(mannequin, wing) temp["colorHref"] = "wing_color" + if(mannequin.wing_style.extra_overlay) + temp["color2"] = MOB_HEX_COLOR(mannequin, wing2) + temp["colorHref2"] = "wing_color2" styles["Wing"] = temp temp = list("styleHref" = "hair_style", "style" = mannequin.h_style) @@ -143,74 +190,74 @@ data["disk"] = disk ? 1 : 0 data["diskStored"] = disk && disk.stored ? 1 : 0 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "body_designer.tmpl", "Body Design Console", 400, 600) - ui.set_initial_data(data) - ui.open() + return data -/obj/machinery/computer/transhuman/designer/Topic(href, href_list) +/obj/machinery/computer/transhuman/designer/tgui_act(action, params) if(..()) - return 1 + return TRUE - else if(href_list["debug_load_my_body"]) - active_br = new /datum/transhuman/body_record(usr, FALSE, FALSE) - preview_icon = null + switch(action) + if("debug_load_my_body") + active_br = new /datum/transhuman/body_record(usr, FALSE, FALSE) + update_preview_icon() + menu = MENU_SPECIFICRECORD - else if (href_list["view_brec"]) - var/datum/transhuman/body_record/BR = locate(href_list["view_brec"]) - if(BR && istype(BR.mydna)) - if(allowed(usr) || BR.ckey == usr.ckey) - active_br = new /datum/transhuman/body_record(BR) // Load a COPY! - preview_icon = null - menu = 4 + if("view_brec") + var/datum/transhuman/body_record/BR = locate(params["view_brec"]) + if(BR && istype(BR.mydna)) + if(allowed(usr) || BR.ckey == usr.ckey) + active_br = new /datum/transhuman/body_record(BR) // Load a COPY! + update_preview_icon() + menu = MENU_SPECIFICRECORD + else + active_br = null + temp = "Access denied: Body records are confidential." else active_br = null - temp = "Access denied: Body records are confidential." - else - active_br = null - temp = "ERROR: Record missing." + temp = "ERROR: Record missing." - else if(href_list["view_stock_brec"]) - var/datum/species/S = GLOB.all_species[href_list["view_stock_brec"]] - if(S && (S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_CAN_JOIN)) == SPECIES_CAN_JOIN) - // Generate body record from species! - mannequin = new(null, S.name) - mannequin.real_name = "Stock [S.name] Body" - mannequin.name = mannequin.real_name - mannequin.dna.real_name = mannequin.real_name - active_br = new(mannequin, FALSE, FALSE) - active_br.speciesname = "Custom Sleeve" - preview_icon = null - menu = 4 - else - active_br = null - temp = "ERROR: Stock Record missing." + if("view_stock_brec") + var/datum/species/S = GLOB.all_species[params["view_stock_brec"]] + if(S && (S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_CAN_JOIN)) == SPECIES_CAN_JOIN) + // Generate body record from species! + mannequin = new(null, S.name) + mannequin.real_name = "Stock [S.name] Body" + mannequin.name = mannequin.real_name + mannequin.dna.real_name = mannequin.real_name + active_br = new(mannequin, FALSE, FALSE) + active_br.speciesname = "Custom Sleeve" + update_preview_icon() + menu = MENU_SPECIFICRECORD + else + active_br = null + temp = "ERROR: Stock Record missing." - else if (href_list["boocnotes"]) - menu = 6 + if("boocnotes") + menu = MENU_OOCNOTES - else if (href_list["loadfromdisk"]) - if(disk && disk.stored) - active_br = new /datum/transhuman/body_record(disk.stored) // Loads a COPY! - preview_icon = null + if("loadfromdisk") + if(disk && disk.stored) + active_br = new /datum/transhuman/body_record(disk.stored) // Loads a COPY! + update_preview_icon() + menu = MENU_SPECIFICRECORD - else if (href_list["savetodisk"]) - if(disk && active_br) - disk.stored = new /datum/transhuman/body_record(active_br) // Saves a COPY! - disk.name = "[initial(disk.name)] ([active_br.mydna.name])" + if("savetodisk") + if(disk && active_br) + disk.stored = new /datum/transhuman/body_record(active_br) // Saves a COPY! + disk.name = "[initial(disk.name)] ([active_br.mydna.name])" + disk.forceMove(get_turf(src)) + disk = null + + if("ejectdisk") disk.forceMove(get_turf(src)) disk = null - else if (href_list["ejectdisk"]) - disk.forceMove(get_turf(src)) - disk = null - - else if (href_list["menu"]) - menu = href_list["menu"] - temp = "" - else - OnTopic(href, href_list, usr) + if("menu") + menu = params["menu"] + temp = "" + + if("href_conversion") + PrefHrefMiddleware(params, usr) add_fingerprint(usr) return 1 // Return 1 to refresh UI @@ -226,24 +273,27 @@ mannequin.delete_inventory(TRUE) update_preview_mob(mannequin) + COMPILE_OVERLAYS(mannequin) + + var/mutable_appearance/MA = new(mannequin) + south_preview.appearance = MA + south_preview.dir = SOUTH + south_preview.screen_loc = "[map_name]:1,1" + south_preview.name = "" + east_preview.appearance = MA + east_preview.dir = EAST + east_preview.screen_loc = "[map_name]:2,1" + east_preview.name = "" + west_preview.appearance = MA + west_preview.dir = WEST + west_preview.screen_loc = "[map_name]:0,1" + west_preview.name = "" - preview_icon = icon('icons/effects/effects.dmi', "nothing") - preview_icon.Scale(48+32, 16+32) +/obj/machinery/computer/transhuman/designer/proc/give_client_previews(client/C) + C.register_map_obj(south_preview) + C.register_map_obj(east_preview) + C.register_map_obj(west_preview) - mannequin.dir = NORTH - var/icon/stamp = getFlatIcon(mannequin) - preview_icon.Blend(stamp, ICON_OVERLAY, 25, 17) - - mannequin.dir = WEST - stamp = getFlatIcon(mannequin) - preview_icon.Blend(stamp, ICON_OVERLAY, 1, 9) - - mannequin.dir = SOUTH - stamp = getFlatIcon(mannequin) - preview_icon.Blend(stamp, ICON_OVERLAY, 49, 1) - - preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. - return preview_icon /obj/machinery/computer/transhuman/designer/proc/update_preview_mob(var/mob/living/carbon/human/H) ASSERT(!QDELETED(H)) @@ -306,15 +356,15 @@ // Problem is, those procs save their data to /datum/preferences, not a body_record. // Luckily the procs to convert from body_record to /datum/preferences and back already exist. // Its ugly, but I think its still better than duplicating and maintaining all that code. -/obj/machinery/computer/transhuman/designer/proc/OnTopic(var/href,var/list/href_list, var/mob/user) - if(!mannequin || !preview_icon || !active_br) +/obj/machinery/computer/transhuman/designer/proc/PrefHrefMiddleware(list/params, var/mob/user) + if(!mannequin || !active_br) return - if(href_list["size_multiplier"]) + if(params["target_href"] == "size_multiplier") var/new_size = input(user, "Choose your character's size, ranging from 25% to 200%", "Character Preference") as num|null if(new_size && ISINRANGE(new_size,25,200)) active_br.sizemult = (new_size/100) - preview_icon = null + update_preview_icon() return 1 // The black magic horror show begins @@ -338,26 +388,30 @@ var/datum/category_item/player_setup_item/vore/ears/E = CG.items_by_name["Appearance"] ASSERT(istype(E)) - if(href_list["bio_gender"]) + if(params["target_href"] == "bio_gender") var/new_gender = input(user, "Choose your character's biological gender:", "Character Preference", active_br.bodygender) as null|anything in G.get_genders() if(new_gender) active_br.bodygender = new_gender active_br.mydna.dna.SetUIState(DNA_UI_GENDER, new_gender!=MALE, 1) - preview_icon = null + update_preview_icon() return 1 + var/href_list = list() + href_list["src"] = "\ref[src]" + href_list["[params["target_href"]]"] = params["target_value"] + var/action = 0 - action = B.OnTopic(href, href_list, user) + action = B.OnTopic(list2params(href_list), href_list, user) if(action & TOPIC_UPDATE_PREVIEW && mannequin && active_br) B.copy_to_mob(mannequin) active_br.mydna.dna.ResetUIFrom(mannequin) - preview_icon = null + update_preview_icon() return 1 - action = E.OnTopic(href, href_list, user) + action = E.OnTopic(list2params(href_list), href_list, user) if(action & TOPIC_UPDATE_PREVIEW && mannequin && active_br) E.copy_to_mob(mannequin) active_br.mydna.dna.ResetUIFrom(mannequin) - preview_icon = null + update_preview_icon() return 1 // Fake subtype of preferences we can use to steal code from player_setup diff --git a/code/modules/resleeving/infomorph.dm b/code/modules/resleeving/infomorph.dm index 45c5d4193b..7fd716bc96 100644 --- a/code/modules/resleeving/infomorph.dm +++ b/code/modules/resleeving/infomorph.dm @@ -417,7 +417,7 @@ var/list/infomorph_emotions = list( desc = "Modify the settings on your integrated radio." if(radio) - radio.ui_interact(src,"main",null,1,conscious_state) + radio.tgui_interact(src) else to_chat(src, "You don't have a radio!") diff --git a/code/modules/shieldgen/shield_capacitor.dm b/code/modules/shieldgen/shield_capacitor.dm index 2ef3f17a85..d76a18045a 100644 --- a/code/modules/shieldgen/shield_capacitor.dm +++ b/code/modules/shieldgen/shield_capacitor.dm @@ -18,6 +18,7 @@ use_power = USE_POWER_OFF //doesn't use APC power var/charge_rate = 100000 //100 kW var/obj/machinery/shield_gen/owned_gen + interact_offline = TRUE /obj/machinery/shield_capacitor/advanced name = "advanced shield capacitor" @@ -67,36 +68,30 @@ /obj/machinery/shield_capacitor/attack_hand(mob/user) if(stat & (BROKEN)) return - interact(user) + tgui_interact(user) -/obj/machinery/shield_capacitor/interact(mob/user) - if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN)) ) - if (!istype(user, /mob/living/silicon)) - user.unset_machine() - user << browse(null, "window=shield_capacitor") - return - var/t = "Shield Capacitor Control Console

" - if(locked) - t += "Swipe your ID card to begin." - else - t += "This capacitor is: [active ? "Online" : "Offline" ] [active ? "\[Deactivate\]" : "\[Activate\]"]
" - t += "Capacitor Status: [time_since_fail > 2 ? "OK." : "Discharging!"]
" - t += "Stored Energy: [format_SI(stored_charge, "J")] ([100 * round(stored_charge/max_charge, 0.01)]%)
" - t += "Charge Rate: \ - \[----\] \ - \[---\] \ - \[--\] \ - \[-\][format_SI(charge_rate, "W")]\ - \[+\] \ - \[++\] \ - \[+++\] \ - \[++++\]
" - t += "
" - t += "Refresh " - t += "Close
" +/obj/machinery/shield_capacitor/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ShieldCapacitor", name) + ui.open() - user << browse(t, "window=shield_capacitor;size=500x400") - user.set_machine(src) +/obj/machinery/shield_capacitor/tgui_status(mob/user) + if(stat & BROKEN) + return STATUS_CLOSE + return ..() + +/obj/machinery/shield_capacitor/tgui_data(mob/user) + var/list/data = list() + + data["active"] = active + data["time_since_fail"] = time_since_fail + data["stored_charge"] = stored_charge + data["max_charge"] = max_charge + data["charge_rate"] = charge_rate + data["max_charge_rate"] = max_charge_rate + + return data /obj/machinery/shield_capacitor/process() if (!anchored) @@ -119,21 +114,20 @@ time_since_fail = 0 //losing charge faster than we can draw from PN last_stored_charge = stored_charge -/obj/machinery/shield_capacitor/Topic(href, href_list[]) - ..() - if( href_list["close"] ) - usr << browse(null, "window=shield_capacitor") - usr.unset_machine() - return - if( href_list["toggle"] ) - if(!active && !anchored) - to_chat(usr, "The [src] needs to be firmly secured to the floor first.") - return - active = !active - if( href_list["charge_rate"] ) - charge_rate = between(10000, charge_rate + text2num(href_list["charge_rate"]), max_charge_rate) +/obj/machinery/shield_capacitor/tgui_act(action, params) + if(..()) + return TRUE - updateDialog() + switch(action) + if("toggle") + if(!active && !anchored) + to_chat(usr, "The [src] needs to be firmly secured to the floor first.") + return + active = !active + . = TRUE + if("charge_rate") + charge_rate = clamp(text2num(params["rate"]), 10000, max_charge_rate) + . = TRUE /obj/machinery/shield_capacitor/power_change() if(stat & BROKEN) diff --git a/code/modules/shieldgen/shield_gen.dm b/code/modules/shieldgen/shield_gen.dm index cdd16d2429..b87f66432f 100644 --- a/code/modules/shieldgen/shield_gen.dm +++ b/code/modules/shieldgen/shield_gen.dm @@ -23,6 +23,7 @@ var/energy_conversion_rate = 0.0006 //how many renwicks per watt? Higher numbers equals more effiency. var/z_range = 0 // How far 'up and or down' to extend the shield to, in z-levels. Only works on MultiZ supported z-levels. use_power = USE_POWER_OFF //doesn't use APC power + interact_offline = TRUE // don't check stat & NOPOWER|BROKEN for our UI. We check BROKEN ourselves. var/id //for button usage /obj/machinery/shield_gen/advanced @@ -95,59 +96,50 @@ /obj/machinery/shield_gen/attack_hand(mob/user) if(stat & (BROKEN)) return - interact(user) + tgui_interact(user) -/obj/machinery/shield_gen/interact(mob/user) - if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN)) ) - if (!istype(user, /mob/living/silicon)) - user.unset_machine() - user << browse(null, "window=shield_generator") - return - var/t = "Shield Generator Control Console

" - if(locked) - t += "Swipe your ID card to begin." - else - t += "[capacitors.len ? "Charge capacitor(s) connected." : "Unable to locate charge capacitor!"]
" - var/i = 0 - for(var/obj/machinery/shield_capacitor/capacitor in capacitors) - i++ - t += "Capacitor #[i]: [capacitor.active ? "Online." : "Offline."] \ - Charge: [round(capacitor.stored_charge/1000, 0.1)] kJ ([100 * round(capacitor.stored_charge/capacitor.max_charge, 0.01)]%) \ - Status: [capacitor.time_since_fail > 2 ? "OK." : "Discharging!"]
" - t += "This generator is: [active ? "Online" : "Offline" ] [active ? "\[Deactivate\]" : "\[Activate\]"]
" - t += "Field Status: [time_since_fail > 2 ? "Stable" : "Unstable"]
" - t += "Coverage Radius (restart required): \ - --- \ - -- \ - - \ - [field_radius] m \ - + \ - ++ \ - +++
" - if(HasAbove(src.z) || HasBelow(src.z)) // Won't show up on maps lacking MultiZ support. - t += "Vertical Shielding (restart required): \ - - \ - [z_range] Vertical Range \ - +
" - t += "Overall Field Strength: [round(average_field_strength, 0.01)] Renwick ([target_field_strength ? round(100 * average_field_strength / target_field_strength, 0.1) : "NA"]%)
" - t += "Upkeep Power: [format_SI(round(field.len * max(average_field_strength * dissipation_rate, min_dissipation) / energy_conversion_rate), "W")]
" - t += "Charge Rate: -- \ - [strengthen_rate] Renwick/s \ - ++
" - t += "Shield Generation Power: [format_SI(round(field.len * min(strengthen_rate, target_field_strength - average_field_strength) / energy_conversion_rate), "W")]
" - t += "Maximum Field Strength: \ - \[min\] \ - -- \ - - \ - [target_field_strength] Renwick \ - + \ - ++ \ - \[max\]
" - t += "
" - t += "Refresh " - t += "Close
" - user << browse(t, "window=shield_generator;size=500x400") - user.set_machine(src) +/obj/machinery/shield_gen/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ShieldGenerator", name) + ui.open() + +/obj/machinery/shield_gen/tgui_status(mob/user) + if(stat & BROKEN) + return STATUS_CLOSE + return ..() + +/obj/machinery/shield_gen/tgui_data(mob/user) + var/list/data = list() + + data["locked"] = locked + data["lockedData"] = list() + if(!locked) + data["lockedData"]["capacitors"] = list() + for(var/obj/machinery/shield_capacitor/C in capacitors) + data["lockedData"]["capacitors"].Add(list(list( + "active" = C.active, + "stored_charge" = C.stored_charge, + "max_charge" = C.max_charge, + "failing" = (C.time_since_fail <= 2), + ))) + + data["lockedData"]["active"] = active + data["lockedData"]["failing"] = (time_since_fail <= 2) + data["lockedData"]["radius"] = field_radius + data["lockedData"]["max_radius"] = max_field_radius + data["lockedData"]["z_range"] = z_range + data["lockedData"]["max_z_range"] = 10 + data["lockedData"]["average_field_strength"] = average_field_strength + data["lockedData"]["target_field_strength"] = target_field_strength + data["lockedData"]["max_field_strength"] = max_field_strength + data["lockedData"]["shields"] = LAZYLEN(field) + data["lockedData"]["upkeep"] = round(field.len * max(average_field_strength * dissipation_rate, min_dissipation) / energy_conversion_rate) + data["lockedData"]["strengthen_rate"] = strengthen_rate + data["lockedData"]["max_strengthen_rate"] = max_strengthen_rate + data["lockedData"]["gen_power"] = round(field.len * min(strengthen_rate, target_field_strength - average_field_strength) / energy_conversion_rate) + + return data /obj/machinery/shield_gen/process() if (!anchored && active) @@ -206,30 +198,32 @@ else average_field_strength = 0 -/obj/machinery/shield_gen/Topic(href, href_list[]) - ..() - if( href_list["close"] ) - usr << browse(null, "window=shield_generator") - usr.unset_machine() - return - else if( href_list["toggle"] ) - if (!active && !anchored) - to_chat(usr, "The [src] needs to be firmly secured to the floor first.") - return - toggle() - else if( href_list["change_radius"] ) - field_radius = between(0, field_radius + text2num(href_list["change_radius"]), max_field_radius) - else if( href_list["strengthen_rate"] ) - strengthen_rate = between(0, strengthen_rate + text2num(href_list["strengthen_rate"]), max_strengthen_rate) - else if( href_list["target_field_strength"] ) - target_field_strength = between(1, target_field_strength + text2num(href_list["target_field_strength"]), max_field_strength) - else if( href_list["z_range"] ) - z_range = between(0, z_range + text2num(href_list["z_range"]), 10) // Max is extending ten z-levels up and down. Probably too big of a number but it shouldn't matter. +/obj/machinery/shield_gen/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("toggle") + if (!active && !anchored) + to_chat(usr, "The [src] needs to be firmly secured to the floor first.") + return + toggle() + . = TRUE + if("change_radius") + field_radius = clamp(text2num(params["val"]), 0, max_field_radius) + . = TRUE + if("strengthen_rate") + strengthen_rate = clamp(text2num(params["val"]), 0, max_strengthen_rate) + . = TRUE + if("target_field_strength") + target_field_strength = clamp(text2num(params["val"]), 1, max_field_strength) + . = TRUE + if("z_range") + z_range = clamp(text2num(params["val"]), 0, 10) + . = TRUE - updateDialog() /obj/machinery/shield_gen/ex_act(var/severity) - if(active) toggle() return ..() diff --git a/code/modules/shuttles/escape_pods.dm b/code/modules/shuttles/escape_pods.dm index 245b96e82e..b1d3efdc0c 100644 --- a/code/modules/shuttles/escape_pods.dm +++ b/code/modules/shuttles/escape_pods.dm @@ -46,73 +46,58 @@ name = "escape pod controller" program = /datum/computer/file/embedded_program/docking/simple var/datum/shuttle/autodock/ferry/escape_pod/pod + valid_actions = list("toggle_override", "force_door") -/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/tgui_data(mob/user) var/datum/computer/file/embedded_program/docking/simple/docking_program = program // Cast to proper type - data = list( + . = list( "docking_status" = docking_program.get_docking_status(), "override_enabled" = docking_program.override_enabled, - "door_state" = docking_program.memory["door_status"]["state"], - "door_lock" = docking_program.memory["door_status"]["lock"], + "exterior_status" = docking_program.memory["door_status"], "can_force" = pod.can_force() || (emergency_shuttle.departed && pod.can_launch()), //allow players to manually launch ahead of time if the shuttle leaves - "is_armed" = pod.arming_controller.armed, + "armed" = pod.arming_controller.armed, + "internalTemplateName" = "EscapePodConsole", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "escape_pod_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/Topic(href, href_list) - if((. = ..())) - return - - if("manual_arm") - pod.arming_controller.arm() - return TOPIC_REFRESH - if("force_launch") - if (pod.can_force()) - pod.force_launch(src) - else if (emergency_shuttle.departed && pod.can_launch()) //allow players to manually launch ahead of time if the shuttle leaves - pod.launch(src) - return TOPIC_REFRESH - return 0 +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/tgui_act(action, params) + if(..()) + return TRUE + switch(action) + if("manual_arm") + pod.arming_controller.arm() + . = TRUE + if("force_launch") + if(pod.can_force()) + pod.force_launch(src) + else if(emergency_shuttle.departed && pod.can_launch()) //allow players to manually launch ahead of time if the shuttle leaves + pod.launch(src) + . = TRUE //This controller is for the escape pod berth (station side) /obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth name = "escape pod berth controller" program = /datum/computer/file/embedded_program/docking/simple/escape_pod_berth + valid_actions = list("toggle_override", "force_door") -/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth/tgui_data(mob/user) var/datum/computer/file/embedded_program/docking/simple/docking_program = program // Cast to proper type var/armed = null - if (istype(docking_program, /datum/computer/file/embedded_program/docking/simple/escape_pod_berth)) + if(istype(docking_program, /datum/computer/file/embedded_program/docking/simple/escape_pod_berth)) var/datum/computer/file/embedded_program/docking/simple/escape_pod_berth/P = docking_program armed = P.armed - data = list( + . = list( "docking_status" = docking_program.get_docking_status(), "override_enabled" = docking_program.override_enabled, + "exterior_status" = docking_program.memory["door_status"], "armed" = armed, + "internalTemplateName" = "EscapePodBerthConsole", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "escape_pod_berth_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - /obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth/emag_act(var/remaining_charges, var/mob/user) if (!emagged) to_chat(user, "You emag the [src], arming the escape pod!") diff --git a/code/modules/tgui/modules/_base.dm b/code/modules/tgui/modules/_base.dm index 46dbc655ff..cefe49230f 100644 --- a/code/modules/tgui/modules/_base.dm +++ b/code/modules/tgui/modules/_base.dm @@ -26,6 +26,9 @@ Code is pretty much ripped verbatim from nano modules, but with un-needed stuff if(host) host.tgui_close(user) +/datum/tgui_module/proc/can_still_topic(mob/user, datum/tgui_state/state) + return (tgui_status(user, state) == STATUS_INTERACTIVE) + /datum/tgui_module/proc/check_access(mob/user, access) if(!access) return 1 @@ -76,4 +79,37 @@ Code is pretty much ripped verbatim from nano modules, but with un-needed stuff ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, tgui_id, name) - ui.open() \ No newline at end of file + ui.open() + +// This is a helper for anything that wants to render the map. +/datum/tgui_module/proc/get_plane_masters() + . = list() + // 'Utility' planes + . += new /obj/screen/plane_master/fullbright //Lighting system (lighting_overlay objects) + . += new /obj/screen/plane_master/lighting //Lighting system (but different!) + . += new /obj/screen/plane_master/ghosts //Ghosts! + . += new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye! + + . += new /obj/screen/plane_master{plane = PLANE_CH_STATUS} //Status is the synth/human icon left side of medhuds + . += new /obj/screen/plane_master{plane = PLANE_CH_HEALTH} //Health bar + . += new /obj/screen/plane_master{plane = PLANE_CH_LIFE} //Alive-or-not icon + . += new /obj/screen/plane_master{plane = PLANE_CH_ID} //Job ID icon + . += new /obj/screen/plane_master{plane = PLANE_CH_WANTED} //Wanted status + . += new /obj/screen/plane_master{plane = PLANE_CH_IMPLOYAL} //Loyalty implants + . += new /obj/screen/plane_master{plane = PLANE_CH_IMPTRACK} //Tracking implants + . += new /obj/screen/plane_master{plane = PLANE_CH_IMPCHEM} //Chemical implants + . += new /obj/screen/plane_master{plane = PLANE_CH_SPECIAL} //"Special" role stuff + . += new /obj/screen/plane_master{plane = PLANE_CH_STATUS_OOC} //OOC status HUD + + . += new /obj/screen/plane_master{plane = PLANE_ADMIN1} //For admin use + . += new /obj/screen/plane_master{plane = PLANE_ADMIN2} //For admin use + . += new /obj/screen/plane_master{plane = PLANE_ADMIN3} //For admin use + + . += new /obj/screen/plane_master{plane = PLANE_MESONS} //Meson-specific things like open ceilings. + . += new /obj/screen/plane_master{plane = PLANE_BUILDMODE} //Things that only show up while in build mode + + // Real tangible stuff planes + . += new /obj/screen/plane_master/main{plane = TURF_PLANE} + . += new /obj/screen/plane_master/main{plane = OBJ_PLANE} + . += new /obj/screen/plane_master/main{plane = MOB_PLANE} + . += new /obj/screen/plane_master/cloaked //Cloaked atoms! \ No newline at end of file diff --git a/code/modules/tgui/modules/alarm.dm b/code/modules/tgui/modules/alarm.dm new file mode 100644 index 0000000000..2c0c75a6e8 --- /dev/null +++ b/code/modules/tgui/modules/alarm.dm @@ -0,0 +1,138 @@ +/datum/tgui_module/alarm_monitor + name = "Alarm monitor" + tgui_id = "StationAlertConsole" + var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use. + var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user. + +/datum/tgui_module/alarm_monitor/New() + ..() + alarm_handlers = list() + +/datum/tgui_module/alarm_monitor/all +/datum/tgui_module/alarm_monitor/all/New() + ..() + alarm_handlers = SSalarm.all_handlers + +/datum/tgui_module/alarm_monitor/all/robot +/datum/tgui_module/alarm_monitor/all/robot/tgui_state(mob/user) + return GLOB.tgui_self_state + +/datum/tgui_module/alarm_monitor/engineering +/datum/tgui_module/alarm_monitor/engineering/New() + ..() + alarm_handlers = list(atmosphere_alarm, fire_alarm, power_alarm) + +// Subtype for glasses_state +/datum/tgui_module/alarm_monitor/engineering/glasses +/datum/tgui_module/alarm_monitor/engineering/glasses/tgui_state(mob/user) + return GLOB.tgui_glasses_state + +// Subtype for nif_state +/datum/tgui_module/alarm_monitor/engineering/nif +/datum/tgui_module/alarm_monitor/engineering/nif/tgui_state(mob/user) + return GLOB.tgui_nif_state + +// Subtype for NTOS +/datum/tgui_module/alarm_monitor/engineering/ntos + ntos = TRUE + +/datum/tgui_module/alarm_monitor/security +/datum/tgui_module/alarm_monitor/security/New() + ..() + alarm_handlers = list(camera_alarm, motion_alarm) + +// Subtype for glasses_state +/datum/tgui_module/alarm_monitor/security/glasses +/datum/tgui_module/alarm_monitor/security/glasses/tgui_state(mob/user) + return GLOB.tgui_glasses_state + +// Subtype for NTOS +/datum/tgui_module/alarm_monitor/security/ntos + ntos = TRUE + +/datum/tgui_module/alarm_monitor/proc/register_alarm(var/object, var/procName) + for(var/datum/alarm_handler/AH in alarm_handlers) + AH.register_alarm(object, procName) + +/datum/tgui_module/alarm_monitor/proc/unregister_alarm(var/object) + for(var/datum/alarm_handler/AH in alarm_handlers) + AH.unregister_alarm(object) + +/datum/tgui_module/alarm_monitor/proc/all_alarms() + var/z = get_z(tgui_host()) + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.visible_alarms(z) + + return all_alarms + +/datum/tgui_module/alarm_monitor/proc/major_alarms() + var/z = get_z(tgui_host()) + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.major_alarms(z) + + return all_alarms + +// Modified version of above proc that uses slightly less resources, returns 1 if there is a major alarm, 0 otherwise. +/datum/tgui_module/alarm_monitor/proc/has_major_alarms() + var/z = get_z(tgui_host()) + for(var/datum/alarm_handler/AH in alarm_handlers) + if(AH.has_major_alarms(z)) + return 1 + + return 0 + +/datum/tgui_module/alarm_monitor/proc/minor_alarms() + var/z = get_z(tgui_host()) + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + all_alarms += AH.minor_alarms(z) + + return all_alarms + +/datum/tgui_module/alarm_monitor/tgui_act(action, params) + if(..()) + return TRUE + + // Camera stuff is AI only. + // If you're not an AI, this is a read-only UI. + if(!isAI(usr)) + return + + switch(action) + if("switchTo") + var/obj/machinery/camera/C = locate(params["camera"]) in cameranet.cameras + if(!C) + return + + usr.switch_to_camera(C) + return 1 + +/datum/tgui_module/alarm_monitor/tgui_data(mob/user) + var/list/data = list() + + var/categories[0] + var/z = get_z(tgui_host()) + for(var/datum/alarm_handler/AH in alarm_handlers) + categories[++categories.len] = list("category" = AH.category, "alarms" = list()) + for(var/datum/alarm/A in AH.visible_alarms(z)) + var/cameras[0] + var/lost_sources[0] + + if(isAI(user)) + for(var/obj/machinery/camera/C in A.cameras()) + cameras[++cameras.len] = C.tgui_structure() + for(var/datum/alarm_source/AS in A.sources) + if(!AS.source) + lost_sources[++lost_sources.len] = AS.source_name + + categories[categories.len]["alarms"] += list(list( + "name" = "[A.alarm_name()]" + "[A.max_severity() > 1 ? "(MAJOR)" : ""]", + "origin_lost" = A.origin == null, + "has_cameras" = cameras.len, + "cameras" = cameras, + "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : "")) + data["categories"] = categories + + return data diff --git a/code/modules/tgui/modules/appearance_changer.dm b/code/modules/tgui/modules/appearance_changer.dm new file mode 100644 index 0000000000..667fe7e0a0 --- /dev/null +++ b/code/modules/tgui/modules/appearance_changer.dm @@ -0,0 +1,358 @@ +/datum/tgui_module/appearance_changer + name = "Appearance Editor" + tgui_id = "AppearanceChanger" + var/flags = APPEARANCE_ALL_HAIR + var/mob/living/carbon/human/owner = null + var/list/valid_species = list() + var/list/valid_hairstyles = list() + var/list/valid_facial_hairstyles = list() + + var/check_whitelist + var/list/whitelist + var/list/blacklist + + var/customize_usr = FALSE + + // Stuff needed to render the map + var/map_name + var/obj/screen/map_view/cam_screen + var/list/cam_plane_masters + var/obj/screen/background/cam_background + var/obj/screen/skybox/local_skybox + // Needed for moving camera support + var/camera_diff_x = -1 + var/camera_diff_y = -1 + var/camera_diff_z = -1 + +/datum/tgui_module/appearance_changer/New( + var/host, + mob/living/carbon/human/H, + check_species_whitelist = 1, + list/species_whitelist = list(), + list/species_blacklist = list()) + . = ..() + + map_name = "appearance_changer_[REF(src)]_map" + // Initialize map objects + cam_screen = new + cam_screen.name = "screen" + cam_screen.assigned_map = map_name + cam_screen.del_on_map_removal = FALSE + cam_screen.screen_loc = "[map_name]:1,1" + + cam_plane_masters = get_plane_masters() + + for(var/plane in cam_plane_masters) + var/obj/screen/instance = plane + instance.assigned_map = map_name + instance.del_on_map_removal = FALSE + instance.screen_loc = "[map_name]:CENTER" + + local_skybox = new() + local_skybox.assigned_map = map_name + local_skybox.del_on_map_removal = FALSE + local_skybox.screen_loc = "[map_name]:CENTER,CENTER" + cam_plane_masters += local_skybox + + cam_background = new + cam_background.assigned_map = map_name + cam_background.del_on_map_removal = FALSE + reload_cameraview() + + owner = H + check_whitelist = check_species_whitelist + whitelist = species_whitelist + blacklist = species_blacklist + +/datum/tgui_module/appearance_changer/Destroy() + qdel(cam_screen) + QDEL_LIST(cam_plane_masters) + qdel(cam_background) + return ..() + +/datum/tgui_module/appearance_changer/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(usr)) + return TRUE + target = usr + + switch(action) + if("race") + if(can_change(APPEARANCE_RACE) && (params["race"] in valid_species)) + if(target.change_species(params["race"])) + cut_and_generate_data() + return 1 + if("gender") + if(can_change(APPEARANCE_GENDER) && (params["gender"] in get_genders())) + if(target.change_gender(params["gender"])) + cut_and_generate_data() + return 1 + if("gender_id") + if(can_change(APPEARANCE_GENDER) && (params["gender_id"] in all_genders_define_list)) + target.identifying_gender = params["gender_id"] + return 1 + if("skin_tone") + if(can_change_skin_tone()) + var/new_s_tone = input(usr, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", -target.s_tone + 35) as num|null + if(isnum(new_s_tone) && can_still_topic(usr, state)) + new_s_tone = 35 - max(min( round(new_s_tone), 220),1) + return target.change_skin_tone(new_s_tone) + if("skin_color") + if(can_change_skin_color()) + var/new_skin = input(usr, "Choose your character's skin colour: ", "Skin Color", rgb(target.r_skin, target.g_skin, target.b_skin)) as color|null + if(new_skin && can_still_topic(usr, state)) + var/r_skin = hex2num(copytext(new_skin, 2, 4)) + var/g_skin = hex2num(copytext(new_skin, 4, 6)) + var/b_skin = hex2num(copytext(new_skin, 6, 8)) + if(target.change_skin_color(r_skin, g_skin, b_skin)) + update_dna() + return 1 + if("hair") + if(can_change(APPEARANCE_HAIR) && (params["hair"] in valid_hairstyles)) + if(target.change_hair(params["hair"])) + update_dna() + return 1 + if("hair_color") + if(can_change(APPEARANCE_HAIR_COLOR)) + var/new_hair = input("Please select hair color.", "Hair Color", rgb(target.r_hair, target.g_hair, target.b_hair)) as color|null + if(new_hair && can_still_topic(usr, state)) + var/r_hair = hex2num(copytext(new_hair, 2, 4)) + var/g_hair = hex2num(copytext(new_hair, 4, 6)) + var/b_hair = hex2num(copytext(new_hair, 6, 8)) + if(target.change_hair_color(r_hair, g_hair, b_hair)) + update_dna() + return 1 + if("facial_hair") + if(can_change(APPEARANCE_FACIAL_HAIR) && (params["facial_hair"] in valid_facial_hairstyles)) + if(target.change_facial_hair(params["facial_hair"])) + update_dna() + return 1 + if("facial_hair_color") + if(can_change(APPEARANCE_FACIAL_HAIR_COLOR)) + var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(target.r_facial, target.g_facial, target.b_facial)) as color|null + if(new_facial && can_still_topic(usr, state)) + var/r_facial = hex2num(copytext(new_facial, 2, 4)) + var/g_facial = hex2num(copytext(new_facial, 4, 6)) + var/b_facial = hex2num(copytext(new_facial, 6, 8)) + if(target.change_facial_hair_color(r_facial, g_facial, b_facial)) + update_dna() + return 1 + if("eye_color") + if(can_change(APPEARANCE_EYE_COLOR)) + var/new_eyes = input("Please select eye color.", "Eye Color", rgb(target.r_eyes, target.g_eyes, target.b_eyes)) as color|null + if(new_eyes && can_still_topic(usr, state)) + var/r_eyes = hex2num(copytext(new_eyes, 2, 4)) + var/g_eyes = hex2num(copytext(new_eyes, 4, 6)) + var/b_eyes = hex2num(copytext(new_eyes, 6, 8)) + if(target.change_eye_color(r_eyes, g_eyes, b_eyes)) + update_dna() + return 1 + return FALSE + +/datum/tgui_module/appearance_changer/tgui_interact(mob/user, datum/tgui/ui = null, datum/tgui/parent_ui = null, datum/tgui_state/custom_state = GLOB.tgui_default_state) + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(user)) + return TRUE + target = user + + if(!target || !target.species) + return + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + reload_cameraview() + // Register map objects + user.client.register_map_obj(cam_screen) + for(var/plane in cam_plane_masters) + user.client.register_map_obj(plane) + user.client.register_map_obj(cam_background) + // Open UI + ui = new(user, src, tgui_id, name) + ui.open() + if(custom_state) + ui.set_state(custom_state) + +/datum/tgui_module/appearance_changer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + generate_data(check_whitelist, whitelist, blacklist) + differential_check() + + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(usr)) + return TRUE + target = usr + + data["name"] = target.name + data["specimen"] = target.species.name + data["gender"] = target.gender + data["gender_id"] = target.identifying_gender + data["change_race"] = can_change(APPEARANCE_RACE) + if(data["change_race"]) + var/species[0] + for(var/specimen in valid_species) + species[++species.len] = list("specimen" = specimen) + data["species"] = species + + data["change_gender"] = can_change(APPEARANCE_GENDER) + if(data["change_gender"]) + var/genders[0] + for(var/gender in get_genders()) + genders[++genders.len] = list("gender_name" = gender2text(gender), "gender_key" = gender) + data["genders"] = genders + var/id_genders[0] + for(var/gender in all_genders_define_list) + id_genders[++id_genders.len] = list("gender_name" = gender2text(gender), "gender_key" = gender) + data["id_genders"] = id_genders + + data["change_hair"] = can_change(APPEARANCE_HAIR) + if(data["change_hair"]) + var/hair_styles[0] + for(var/hair_style in valid_hairstyles) + hair_styles[++hair_styles.len] = list("hairstyle" = hair_style) + data["hair_styles"] = hair_styles + data["hair_style"] = target.h_style + + data["change_facial_hair"] = can_change(APPEARANCE_FACIAL_HAIR) + if(data["change_facial_hair"]) + var/facial_hair_styles[0] + for(var/facial_hair_style in valid_facial_hairstyles) + facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_style) + data["facial_hair_styles"] = facial_hair_styles + data["facial_hair_style"] = target.f_style + + data["change_skin_tone"] = can_change_skin_tone() + data["change_skin_color"] = can_change_skin_color() + if(data["change_skin_color"]) + data["skin_color"] = rgb(target.r_skin, target.g_skin, target.b_skin) + data["change_eye_color"] = can_change(APPEARANCE_EYE_COLOR) + if(data["change_eye_color"]) + data["eye_color"] = rgb(target.r_eyes, target.g_eyes, target.b_eyes) + data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR) + if(data["change_hair_color"]) + data["hair_color"] = rgb(target.r_hair, target.g_hair, target.b_hair) + data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR) + if(data["change_facial_hair_color"]) + data["facial_hair_color"] = rgb(target.r_facial, target.g_facial, target.b_facial) + return data + +/datum/tgui_module/appearance_changer/tgui_static_data(mob/user) + var/list/data = ..() + data["mapRef"] = map_name + return data + +/datum/tgui_module/appearance_changer/proc/differential_check() + var/turf/T = get_turf(customize_usr ? tgui_host() : owner) + if(T) + var/new_x = T.x + var/new_y = T.y + var/new_z = T.z + if((new_x != camera_diff_x) || (new_y != camera_diff_y) || (new_z != camera_diff_z)) + reload_cameraview() + +/datum/tgui_module/appearance_changer/proc/reload_cameraview() + var/turf/camTurf = get_turf(customize_usr ? tgui_host() : owner) + if(!camTurf) + return + + camera_diff_x = camTurf.x + camera_diff_y = camTurf.y + camera_diff_z = camTurf.z + + var/list/visible_turfs = list() + for(var/turf/T in range(1, camTurf)) + visible_turfs += T + + cam_screen.vis_contents = visible_turfs + cam_background.icon_state = "clear" + cam_background.fill_rect(1, 1, 3, 3) + + local_skybox.cut_overlays() + local_skybox.add_overlay(SSskybox.get_skybox(get_z(camTurf))) + local_skybox.scale_to_view(3) + local_skybox.set_position("CENTER", "CENTER", (world.maxx>>1) - camTurf.x, (world.maxy>>1) - camTurf.y) + +/datum/tgui_module/appearance_changer/proc/update_dna() + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(usr)) + return TRUE + target = usr + + if(target && (flags & APPEARANCE_UPDATE_DNA)) + target.update_dna() + +/datum/tgui_module/appearance_changer/proc/can_change(var/flag) + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(usr)) + return TRUE + target = usr + + return target && (flags & flag) + +/datum/tgui_module/appearance_changer/proc/can_change_skin_tone() + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(usr)) + return TRUE + target = usr + + return target && (flags & APPEARANCE_SKIN) && target.species.appearance_flags & HAS_SKIN_TONE + +/datum/tgui_module/appearance_changer/proc/can_change_skin_color() + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(usr)) + return TRUE + target = usr + + return target && (flags & APPEARANCE_SKIN) && target.species.appearance_flags & HAS_SKIN_COLOR + +/datum/tgui_module/appearance_changer/proc/cut_and_generate_data() + // Making the assumption that the available species remain constant + valid_facial_hairstyles.Cut() + valid_facial_hairstyles.Cut() + generate_data() + +/datum/tgui_module/appearance_changer/proc/generate_data() + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(usr)) + return TRUE + target = usr + if(!target) + return + if(!valid_species.len) + valid_species = target.generate_valid_species(check_whitelist, whitelist, blacklist) + if(!valid_hairstyles.len || !valid_facial_hairstyles.len) + valid_hairstyles = target.generate_valid_hairstyles(check_gender = 0) + valid_facial_hairstyles = target.generate_valid_facial_hairstyles() + +/datum/tgui_module/appearance_changer/proc/get_genders() + var/mob/living/carbon/human/target = owner + if(customize_usr) + if(!ishuman(usr)) + return TRUE + target = usr + var/datum/species/S = target.species + var/list/possible_genders = S.genders + if(!target.internal_organs_by_name["cell"]) + return possible_genders + possible_genders = possible_genders.Copy() + possible_genders |= NEUTER + return possible_genders + +/datum/tgui_module/appearance_changer/mirror + name = "SalonPro Nano-Mirror™" + flags = APPEARANCE_ALL_HAIR + customize_usr = TRUE + +/datum/tgui_module/appearance_changer/mirror/coskit + name = "SalonPro Porta-Makeover Deluxe™" \ No newline at end of file diff --git a/code/modules/tgui/modules/atmos_control.dm b/code/modules/tgui/modules/atmos_control.dm new file mode 100644 index 0000000000..83d3db4d1e --- /dev/null +++ b/code/modules/tgui/modules/atmos_control.dm @@ -0,0 +1,110 @@ +/datum/tgui_module/atmos_control + name = "Atmospherics Control" + tgui_id = "AtmosControl" + var/obj/access = new() + var/emagged = 0 + var/ui_ref + var/list/monitored_alarms = list() + +/datum/tgui_module/atmos_control/New(atmos_computer, req_access, req_one_access, monitored_alarm_ids) + ..() + access.req_access = req_access + access.req_one_access = req_one_access + + if(monitored_alarm_ids) + for(var/obj/machinery/alarm/alarm in machines) + if(alarm.alarm_id && alarm.alarm_id in monitored_alarm_ids) + monitored_alarms += alarm + // machines may not yet be ordered at this point + monitored_alarms = dd_sortedObjectList(monitored_alarms) + +/datum/tgui_module/atmos_control/tgui_act(action, params, datum/tgui/ui) + if(..()) + return TRUE + + switch(action) + if("alarm") + if(ui_ref) + var/obj/machinery/alarm/alarm = locate(params["alarm"]) in (monitored_alarms.len ? monitored_alarms : machines) + if(alarm) + var/datum/tgui_state/TS = generate_state(alarm) + alarm.tgui_interact(usr, parent_ui = ui_ref, state = TS) + return 1 + if("setZLevel") + ui.set_map_z_level(params["mapZLevel"]) + return TRUE + +/datum/tgui_module/atmos_control/tgui_interact(mob/user, datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, tgui_id, name) + ui.autoupdate = TRUE + ui.open() + ui_ref = ui + +/datum/tgui_module/atmos_control/tgui_static_data(mob/user) + . = ..() + + var/z = get_z(user) + var/list/map_levels = using_map.get_map_levels(z) + + // TODO: Move these to a cache, similar to cameras + var/alarms[0] + for(var/obj/machinery/alarm/alarm in (monitored_alarms.len ? monitored_alarms : machines)) + if(!monitored_alarms.len && alarm.alarms_hidden) + continue + if(!(alarm.z in map_levels)) + continue + alarms[++alarms.len] = list( + "name" = sanitize(alarm.name), + "ref"= "\ref[alarm]", + "danger" = max(alarm.danger_level, alarm.alarm_area.atmosalm), + "x" = alarm.x, + "y" = alarm.y, + "z" = alarm.z) + .["alarms"] = alarms + +/datum/tgui_module/atmos_control/tgui_data(mob/user) + var/list/data = list() + + var/z = get_z(user) + var/list/map_levels = using_map.get_map_levels(z) + data["map_levels"] = map_levels + + return data + +/datum/tgui_module/atmos_control/tgui_close() + . = ..() + ui_ref = null + +/datum/tgui_module/atmos_control/proc/generate_state(air_alarm) + var/datum/tgui_state/air_alarm_remote/state = new() + state.atmos_control = src + state.air_alarm = air_alarm + return state + +/datum/tgui_state/air_alarm_remote + var/datum/tgui_module/atmos_control/atmos_control = null + var/obj/machinery/alarm/air_alarm = null + +/datum/tgui_state/air_alarm_remote/can_use_topic(src_object, mob/user) + if(!atmos_control.ui_ref) + qdel(src) + return STATUS_CLOSE + if(has_access(user)) + return STATUS_INTERACTIVE + return STATUS_UPDATE + +/datum/tgui_state/air_alarm_remote/proc/has_access(var/mob/user) + return user && (isAI(user) || atmos_control.access.allowed(user) || atmos_control.emagged || air_alarm.rcon_setting == RCON_YES || (air_alarm.alarm_area.atmosalm && air_alarm.rcon_setting == RCON_AUTO) || (access_ce in user.GetAccess())) + +/datum/tgui_state/air_alarm_remote/Destroy() + atmos_control = null + air_alarm = null + +/datum/tgui_module/atmos_control/ntos + ntos = TRUE + +/datum/tgui_module/atmos_control/robot +/datum/tgui_module/atmos_control/robot/tgui_state(mob/user) + return GLOB.tgui_self_state \ No newline at end of file diff --git a/code/modules/tgui/modules/camera.dm b/code/modules/tgui/modules/camera.dm index e1223fad74..d9ac311ee3 100644 --- a/code/modules/tgui/modules/camera.dm +++ b/code/modules/tgui/modules/camera.dm @@ -37,37 +37,7 @@ cam_screen.del_on_map_removal = FALSE cam_screen.screen_loc = "[map_name]:1,1" - cam_plane_masters = list() - - // 'Utility' planes - cam_plane_masters += new /obj/screen/plane_master/fullbright //Lighting system (lighting_overlay objects) - cam_plane_masters += new /obj/screen/plane_master/lighting //Lighting system (but different!) - cam_plane_masters += new /obj/screen/plane_master/ghosts //Ghosts! - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye! - - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_STATUS} //Status is the synth/human icon left side of medhuds - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_HEALTH} //Health bar - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_LIFE} //Alive-or-not icon - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_ID} //Job ID icon - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_WANTED} //Wanted status - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_IMPLOYAL} //Loyalty implants - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_IMPTRACK} //Tracking implants - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_IMPCHEM} //Chemical implants - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_SPECIAL} //"Special" role stuff - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_CH_STATUS_OOC} //OOC status HUD - - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_ADMIN1} //For admin use - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_ADMIN2} //For admin use - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_ADMIN3} //For admin use - - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_MESONS} //Meson-specific things like open ceilings. - cam_plane_masters += new /obj/screen/plane_master{plane = PLANE_BUILDMODE} //Things that only show up while in build mode - - // Real tangible stuff planes - cam_plane_masters += new /obj/screen/plane_master/main{plane = TURF_PLANE} - cam_plane_masters += new /obj/screen/plane_master/main{plane = OBJ_PLANE} - cam_plane_masters += new /obj/screen/plane_master/main{plane = MOB_PLANE} - cam_plane_masters += new /obj/screen/plane_master/cloaked //Cloaked atoms! + cam_plane_masters = get_plane_masters() for(var/plane in cam_plane_masters) var/obj/screen/instance = plane diff --git a/code/modules/tgui/modules/power_monitor.dm b/code/modules/tgui/modules/power_monitor.dm new file mode 100644 index 0000000000..ec5c820598 --- /dev/null +++ b/code/modules/tgui/modules/power_monitor.dm @@ -0,0 +1,85 @@ +/datum/tgui_module/power_monitor + name = "Power monitor" + tgui_id = "PowerMonitor" + var/list/grid_sensors + var/active_sensor = null //name_tag of the currently selected sensor + +/datum/tgui_module/power_monitor/New() + . = ..() + refresh_sensors() + +/datum/tgui_module/power_monitor/tgui_data(mob/user) + var/list/data = list() + + var/list/sensors = list() + // Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading. + var/obj/machinery/power/sensor/focus = null + + var/z = get_z(user) + var/list/map_levels = using_map.get_map_levels(z) + + // Build list of data from sensor readings. + for(var/obj/machinery/power/sensor/S in grid_sensors) + if(!(S.z in map_levels)) + continue + sensors.Add(list(list( + "name" = S.name_tag, + "alarm" = S.check_grid_warning() + ))) + if(S.name_tag == active_sensor) + focus = S + + data["all_sensors"] = sensors + if(focus) + data["focus"] = focus.tgui_data(user) + else + data["focus"] = null + + return data + +/datum/tgui_module/power_monitor/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("clear") + active_sensor = null + . = TRUE + if("refresh") + refresh_sensors() + . = TRUE + if("setsensor") + active_sensor = params["id"] + . = TRUE + +/datum/tgui_module/power_monitor/proc/has_alarm() + for(var/obj/machinery/power/sensor/S in grid_sensors) + if(S.check_grid_warning()) + return TRUE + return FALSE + +/datum/tgui_module/power_monitor/proc/refresh_sensors() + grid_sensors = list() + + // Handle ultranested programs + var/turf/T = get_turf(tgui_host()) + + var/list/levels = list() + if(!T) // Safety check + return + if(T) + levels += using_map.get_map_levels(T.z, FALSE) + for(var/obj/machinery/power/sensor/S in machines) + if(T && (S.loc.z == T.z) || (S.loc.z in levels) || (S.long_range)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels. + if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen! + warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z") + else + grid_sensors += S + +/datum/tgui_module/power_monitor/ntos + ntos = TRUE + +// Subtype for self_state +/datum/tgui_module/power_monitor/robot +/datum/tgui_module/power_monitor/robot/tgui_state(mob/user) + return GLOB.tgui_self_state diff --git a/code/modules/tgui/modules/rcon.dm b/code/modules/tgui/modules/rcon.dm new file mode 100644 index 0000000000..62cf3e5d71 --- /dev/null +++ b/code/modules/tgui/modules/rcon.dm @@ -0,0 +1,118 @@ +/datum/tgui_module/rcon + name = "Power RCON" + tgui_id = "RCON" + + var/list/known_SMESs = null + var/list/known_breakers = null + +/datum/tgui_module/rcon/tgui_data(mob/user) + FindDevices() // Update our devices list + var/list/data = ..() + + // SMES DATA (simplified view) + var/list/smeslist[0] + for(var/obj/machinery/power/smes/buildable/SMES in known_SMESs) + smeslist.Add(list(list( + "capacity" = SMES.capacity, + "capacityPercent" = round(100*SMES.charge/SMES.capacity, 0.1), + "charge" = SMES.charge, + "input_set" = SMES.input_attempt, + "input_val" = round(SMES.input_level/1000, 0.1), + "output_set" = SMES.output_attempt, + "output_val" = round(SMES.output_level/1000, 0.1), + "output_load" = round(SMES.output_used/1000, 0.1), + "RCON_tag" = SMES.RCon_tag + ))) + + data["smes_info"] = sortByKey(smeslist, "RCON_tag") + + // BREAKER DATA (simplified view) + var/list/breakerlist[0] + for(var/obj/machinery/power/breakerbox/BR in known_breakers) + breakerlist.Add(list(list( + "RCON_tag" = BR.RCon_tag, + "enabled" = BR.on + ))) + data["breaker_info"] = breakerlist + + return data + +/datum/tgui_module/rcon/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("smes_in_toggle") + var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(params["smes"]) + if(SMES) + SMES.toggle_input() + . = TRUE + if("smes_out_toggle") + var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(params["smes"]) + if(SMES) + SMES.toggle_output() + . = TRUE + if("smes_in_set") + var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(params["smes"]) + if(SMES) + var/inputset = (input(usr, "Enter new input level (0-[SMES.input_level_max/1000] kW)", "SMES Input Power Control", SMES.input_level/1000) as num) * 1000 + SMES.set_input(inputset) + . = TRUE + if("smes_out_set") + var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(params["smes"]) + if(SMES) + var/outputset = (input(usr, "Enter new output level (0-[SMES.output_level_max/1000] kW)", "SMES Output Power Control", SMES.output_level/1000) as num) * 1000 + SMES.set_output(outputset) + . = TRUE + if("toggle_breaker") + var/obj/machinery/power/breakerbox/toggle = null + for(var/obj/machinery/power/breakerbox/breaker in known_breakers) + if(breaker.RCon_tag == params["breaker"]) + toggle = breaker + if(toggle) + if(toggle.update_locked) + to_chat(usr, "The breaker box was recently toggled. Please wait before toggling it again.") + else + toggle.auto_toggle() + . = TRUE + + +// Proc: GetSMESByTag() +// Parameters: 1 (tag - RCON tag of SMES we want to look up) +// Description: Looks up and returns SMES which has matching RCON tag +/datum/tgui_module/rcon/proc/GetSMESByTag(var/tag) + if(!tag) + return + + for(var/obj/machinery/power/smes/buildable/S in known_SMESs) + if(S.RCon_tag == tag) + return S + +// Proc: FindDevices() +// Parameters: None +// Description: Refreshes local list of known devices. +/datum/tgui_module/rcon/proc/FindDevices() + known_SMESs = new /list() + + var/z = get_z(tgui_host()) + var/list/map_levels = using_map.get_map_levels(z) + + for(var/obj/machinery/power/smes/buildable/SMES in GLOB.smeses) + if(!(SMES.z in map_levels)) + continue + if(SMES.RCon_tag && (SMES.RCon_tag != "NO_TAG") && SMES.RCon) + known_SMESs.Add(SMES) + + known_breakers = new /list() + for(var/obj/machinery/power/breakerbox/breaker in machines) + if(!(breaker.z in map_levels)) + continue + if(breaker.RCon_tag != "NO_TAG") + known_breakers.Add(breaker) + +/datum/tgui_module/rcon/ntos + ntos = TRUE + +/datum/tgui_module/rcon/robot +/datum/tgui_module/rcon/robot/tgui_state(mob/user) + return GLOB.tgui_self_state \ No newline at end of file diff --git a/code/modules/tgui/modules/shutoff_monitor.dm b/code/modules/tgui/modules/shutoff_monitor.dm new file mode 100644 index 0000000000..ead6502dc4 --- /dev/null +++ b/code/modules/tgui/modules/shutoff_monitor.dm @@ -0,0 +1,46 @@ +/datum/tgui_module/shutoff_monitor + name = "Shutoff Valve Monitoring" + tgui_id = "ShutoffMonitor" + +/datum/tgui_module/shutoff_monitor/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("toggle_enable") + var/obj/machinery/atmospherics/valve/shutoff/S = locate(params["valve"]) + if(!istype(S)) + return 0 + S.close_on_leaks = !S.close_on_leaks + return 1 + + if("toggle_open") + var/obj/machinery/atmospherics/valve/shutoff/S = locate(params["valve"]) + if(!istype(S)) + return 0 + if(S.open) + S.close() + else + S.open() + return 1 + +/datum/tgui_module/shutoff_monitor/tgui_data(mob/user) + var/list/data = list() + var/list/valves = list() + + for(var/obj/machinery/atmospherics/valve/shutoff/S in GLOB.shutoff_valves) + valves.Add(list(list( + "name" = S.name, + "enabled" = S.close_on_leaks, + "open" = S.open, + "x" = S.x, + "y" = S.y, + "z" = S.z, + "ref" = "\ref[S]" + ))) + + data["valves"] = valves + return data + +/datum/tgui_module/shutoff_monitor/ntos + ntos = TRUE \ No newline at end of file diff --git a/code/modules/tgui/modules/supermatter_monitor.dm b/code/modules/tgui/modules/supermatter_monitor.dm new file mode 100644 index 0000000000..0e0aed4f1b --- /dev/null +++ b/code/modules/tgui/modules/supermatter_monitor.dm @@ -0,0 +1,108 @@ + +/datum/tgui_module/supermatter_monitor + name = "Supermatter monitor" + tgui_id = "SupermatterMonitor" + var/list/supermatters + var/obj/machinery/power/supermatter/active = null // Currently selected supermatter crystal. + +/datum/tgui_module/supermatter_monitor/Destroy() + . = ..() + active = null + supermatters = null + +/datum/tgui_module/supermatter_monitor/New() + ..() + refresh() + +// Refreshes list of active supermatter crystals +/datum/tgui_module/supermatter_monitor/proc/refresh() + supermatters = list() + var/z = get_z(tgui_host()) + if(!z) + return + var/valid_z_levels = using_map.get_map_levels(z) + for(var/obj/machinery/power/supermatter/S in machines) + // Delaminating, not within coverage, not on a tile. + if(S.grav_pulling || S.exploded || !(S.z in valid_z_levels) || !istype(S.loc, /turf/)) + continue + supermatters.Add(S) + + if(!(active in supermatters)) + active = null + +/datum/tgui_module/supermatter_monitor/proc/get_status() + . = SUPERMATTER_INACTIVE + for(var/obj/machinery/power/supermatter/S in supermatters) + . = max(., S.get_status()) + +/datum/tgui_module/supermatter_monitor/tgui_data(mob/user) + var/list/data = ..() + + if(istype(active)) + var/turf/T = get_turf(active) + if(!T) + active = null + return + var/datum/gas_mixture/air = T.return_air() + if(!istype(air)) + active = null + return + + data["active"] = 1 + data["SM_area"] = get_area(active) + data["SM_integrity"] = active.get_integrity() + data["SM_power"] = active.power + data["SM_ambienttemp"] = air.temperature + data["SM_ambientpressure"] = air.return_pressure() + data["SM_EPR"] = active.get_epr() + //data["SM_EPR"] = active.get_epr() + if(air.total_moles) + data["SM_gas_O2"] = round(100*air.gas["oxygen"]/air.total_moles,0.01) + data["SM_gas_CO2"] = round(100*air.gas["carbon_dioxide"]/air.total_moles,0.01) + data["SM_gas_N2"] = round(100*air.gas["nitrogen"]/air.total_moles,0.01) + data["SM_gas_PH"] = round(100*air.gas["phoron"]/air.total_moles,0.01) + data["SM_gas_N2O"] = round(100*air.gas["sleeping_agent"]/air.total_moles,0.01) + else + data["SM_gas_O2"] = 0 + data["SM_gas_CO2"] = 0 + data["SM_gas_N2"] = 0 + data["SM_gas_PH"] = 0 + data["SM_gas_N2O"] = 0 + else + var/list/SMS = list() + for(var/obj/machinery/power/supermatter/S in supermatters) + var/area/A = get_area(S) + if(!A) + continue + + SMS.Add(list(list( + "area_name" = A.name, + "integrity" = S.get_integrity(), + "uid" = S.uid + ))) + + data["active"] = 0 + data["supermatters"] = SMS + + return data + +/datum/tgui_module/supermatter_monitor/tgui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("clear") + active = null + . = TRUE + if("refresh") + refresh() + . = TRUE + if("set") + var/newuid = text2num(params["set"]) + for(var/obj/machinery/power/supermatter/S in supermatters) + if(S.uid == newuid) + active = S + . = TRUE + +/datum/tgui_module/supermatter_monitor/ntos + ntos = TRUE \ No newline at end of file diff --git a/code/modules/turbolift/turbolift_console.dm b/code/modules/turbolift/turbolift_console.dm index d69a9b0a16..9d8b90f802 100644 --- a/code/modules/turbolift/turbolift_console.dm +++ b/code/modules/turbolift/turbolift_console.dm @@ -143,57 +143,56 @@ /obj/structure/lift/panel/interact(var/mob/user) if(!..()) return + + tgui_interact(user) - var/dat = list() - dat += "
Lift panel
" +/obj/structure/lift/panel/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Turbolift", name) + ui.open() - //the floors list stores levels in order of increasing Z - //therefore, to display upper levels at the top of the menu and - //lower levels at the bottom, we need to go through the list in reverse +/obj/structure/lift/panel/tgui_data(mob/user) + var/list/data = list() + + data["doors_open"] = lift.doors_are_open() + data["fire_mode"] = lift.fire_mode + + data["floors"] = list() for(var/i in lift.floors.len to 1 step -1) var/datum/turbolift_floor/floor = lift.floors[i] - var/label = floor.label? floor.label : "Level #[i]" - dat += "" - dat += "[label]: [floor.name]
" + data["floors"].Add(list(list( + "id" = i, + "ref" = "\ref[floor]", + "queued" = (floor in lift.queued_floors), + "target" = (lift.target_floor == floor), + "current" = (lift.current_floor == floor), + "label" = floor.label, + "name" = floor.name, + ))) + + return data - dat += "
" - if(lift.doors_are_open()) - dat += "Close Doors
" - else - dat += "Open Doors
" - dat += "Emergency Stop" - dat += "
" +/obj/structure/lift/panel/tgui_act(action, params) + if(..()) + return TRUE - user.set_machine(src) - var/datum/browser/popup = new(user, "turbolift_panel", "Lift Panel", 350, 320) //VOREStation Edit - Wider! - popup.set_content(jointext(dat, null)) - popup.open() - return + switch(action) + if("move_to_floor") + . = TRUE + lift.queue_move_to(locate(params["ref"])) + if("toggle_doors") + . = TRUE + if(lift.doors_are_open()) + lift.close_doors() + else + lift.open_doors() + if("emergency_stop") + . = TRUE + lift.emergency_stop() -/obj/structure/lift/panel/Topic(href, href_list) - . = ..() if(.) - return - - var/panel_interact - if(href_list["move_to_floor"]) - lift.queue_move_to(locate(href_list["move_to_floor"])) - panel_interact = 1 - if(href_list["open_doors"]) - panel_interact = 1 - lift.open_doors() - if(href_list["close_doors"]) - panel_interact = 1 - lift.close_doors() - if(href_list["emergency_stop"]) - panel_interact = 1 - lift.emergency_stop() - - if(panel_interact) pressed(usr) - updateDialog() - - return 0 /obj/structure/lift/panel/update_icon() if(lift.fire_mode) diff --git a/code/modules/virus2/centrifuge.dm b/code/modules/virus2/centrifuge.dm index 521b74544d..ee2385d90d 100644 --- a/code/modules/virus2/centrifuge.dm +++ b/code/modules/virus2/centrifuge.dm @@ -26,7 +26,7 @@ O.loc = src user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") - SSnanoui.update_uis(src) + SStgui.update_uis(src) src.attack_hand(user) @@ -36,27 +36,32 @@ icon_state = "centrifuge_moving" /obj/machinery/computer/centrifuge/attack_hand(var/mob/user as mob) - if(..()) return - ui_interact(user) + if(..()) + return + tgui_interact(user) -/obj/machinery/computer/centrifuge/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/centrifuge/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "IsolationCentrifuge", name) + ui.open() - var/data[0] +/obj/machinery/computer/centrifuge/tgui_data(mob/user) + var/list/data = list() data["antibodies"] = null - data["pathogens"] = null + data["pathogens"] = list() data["is_antibody_sample"] = null + data["busy"] = null + data["sample_inserted"] = !!sample - if (curing) + if(curing) data["busy"] = "Isolating antibodies..." - else if (isolating) + else if(isolating) data["busy"] = "Isolating pathogens..." else - data["sample_inserted"] = !!sample - - if (sample) + if(sample) var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list - if (B) + if(B) data["antibodies"] = antigens2string(B.data["antibodies"], none=null) var/list/pathogens[0] @@ -65,8 +70,7 @@ var/datum/disease2/disease/V = virus[ID] pathogens.Add(list(list("name" = V.name(), "spread_type" = V.spreadtype, "reference" = "\ref[V]"))) - if (pathogens.len > 0) - data["pathogens"] = pathogens + data["pathogens"] = pathogens else var/datum/reagent/antibodies/A = locate(/datum/reagent/antibodies) in sample.reagents.reagent_list @@ -74,103 +78,90 @@ data["antibodies"] = antigens2string(A.data["antibodies"], none=null) data["is_antibody_sample"] = 1 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "isolation_centrifuge.tmpl", src.name, 400, 500) - ui.set_initial_data(data) - ui.open() + return data /obj/machinery/computer/centrifuge/process() ..() - if (stat & (NOPOWER|BROKEN)) return + if(stat & (NOPOWER|BROKEN)) return - if (curing) + if(curing) curing -= 1 - if (curing == 0) + if(curing == 0) cure() - if (isolating) + if(isolating) isolating -= 1 if(isolating == 0) isolate() -/obj/machinery/computer/centrifuge/Topic(href, href_list) - if (..()) return 1 +/obj/machinery/computer/centrifuge/tgui_act(action, params) + if(..()) + return TRUE var/mob/user = usr - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") + add_fingerprint(user) - src.add_fingerprint(user) - if (href_list["close"]) - user.unset_machine() - ui.close() - return 0 - - if (href_list["print"]) - print(user) - return 1 - - if(href_list["isolate"]) - var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list - if (B) - var/datum/disease2/disease/virus = locate(href_list["isolate"]) - virus2 = virus.getcopy() - isolating = 40 - update_icon() - return 1 - - switch(href_list["action"]) - if ("antibody") + switch(action) + if("print") + print(user) + . = TRUE + if("isolate") + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list + if(B) + var/datum/disease2/disease/virus = locate(params["isolate"]) + virus2 = virus.getcopy() + isolating = 40 + update_icon() + . = TRUE + if("antibody") var/delay = 20 var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list - if (!B) + if(!B) state("\The [src] buzzes, \"No antibody carrier detected.\"", "blue") - return 1 + return TRUE var/has_toxins = locate(/datum/reagent/toxin) in sample.reagents.reagent_list var/has_radium = sample.reagents.has_reagent("radium") - if (has_toxins || has_radium) + if(has_toxins || has_radium) state("\The [src] beeps, \"Pathogen purging speed above nominal.\"", "blue") - if (has_toxins) + if(has_toxins) delay = delay/2 - if (has_radium) + if(has_radium) delay = delay/2 curing = round(delay) playsound(src, 'sound/machines/juicer.ogg', 50, 1) update_icon() - return 1 - + . = TRUE if("sample") if(sample) sample.loc = src.loc sample = null - return 1 + . = TRUE - return 0 /obj/machinery/computer/centrifuge/proc/cure() - if (!sample) return + if(!sample) return var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list - if (!B) return + if(!B) return var/list/data = list("antibodies" = B.data["antibodies"]) var/amt= sample.reagents.get_reagent_amount("blood") sample.reagents.remove_reagent("blood", amt) sample.reagents.add_reagent("antibodies", amt, data) - SSnanoui.update_uis(src) + SStgui.update_uis(src) update_icon() ping("\The [src] pings, \"Antibody isolated.\"") /obj/machinery/computer/centrifuge/proc/isolate() - if (!sample) return + if(!sample) return var/obj/item/weapon/virusdish/dish = new/obj/item/weapon/virusdish(loc) dish.virus2 = virus2 virus2 = null - SSnanoui.update_uis(src) + SStgui.update_uis(src) update_icon() ping("\The [src] pings, \"Pathogen isolated.\"") @@ -182,20 +173,20 @@ Sample: [sample.name]
"} - if (user) + if(user) P.info += "Generated By: [user.name]
" P.info += "
" var/datum/reagent/blood/B = locate(/datum/reagent/blood) in sample.reagents.reagent_list - if (B) + if(B) P.info += "Antibodies: " P.info += antigens2string(B.data["antibodies"]) P.info += "
" var/list/virus = B.data["virus2"] P.info += "Pathogens:
" - if (virus.len > 0) + if(virus.len > 0) for (var/ID in virus) var/datum/disease2/disease/V = virus[ID] P.info += "[V.name()]
" @@ -204,7 +195,7 @@ else var/datum/reagent/antibodies/A = locate(/datum/reagent/antibodies) in sample.reagents.reagent_list - if (A) + if(A) P.info += "The following antibodies have been isolated from the blood sample: " P.info += antigens2string(A.data["antibodies"]) P.info += "
" diff --git a/code/modules/virus2/disease2.dm b/code/modules/virus2/disease2.dm index e163478b77..9d37b1db29 100644 --- a/code/modules/virus2/disease2.dm +++ b/code/modules/virus2/disease2.dm @@ -254,6 +254,7 @@ var/global/list/virusDB = list() "resistance" = resistance, "species" = jointext(affected_species, ", "), "symptoms" = list(), + "ref" = "\ref[src]", ) for(var/datum/disease2/effectholder/E in effects) @@ -272,6 +273,7 @@ var/global/list/virusDB = list() v.fields["name"] = name() v.fields["description"] = get_info() v.fields["tgui_description"] = get_tgui_info() + v.fields["tgui_description"]["record"] = "\ref[v]" v.fields["antigen"] = antigens2string(antigen) v.fields["spread type"] = spreadtype virusDB["[uniqueID]"] = v diff --git a/code/modules/virus2/diseasesplicer.dm b/code/modules/virus2/diseasesplicer.dm index 95657498a0..fb682f51d1 100644 --- a/code/modules/virus2/diseasesplicer.dm +++ b/code/modules/virus2/diseasesplicer.dm @@ -20,7 +20,7 @@ if(istype(I,/obj/item/weapon/virusdish)) var/mob/living/carbon/c = user - if (dish) + if(dish) to_chat(user, "\The [src] is already loaded.") return @@ -40,36 +40,46 @@ return src.attack_hand(user) /obj/machinery/computer/diseasesplicer/attack_hand(var/mob/user as mob) - if(..()) return - ui_interact(user) + if(..()) + return TRUE + tgui_interact(user) -/obj/machinery/computer/diseasesplicer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/diseasesplicer/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "DiseaseSplicer", name) + ui.open() - var/data[0] +/obj/machinery/computer/diseasesplicer/tgui_data(mob/user) + var/list/data = list() data["dish_inserted"] = !!dish - data["growth"] = 0 - data["affected_species"] = null - if (memorybank) + data["buffer"] = null + if(memorybank) data["buffer"] = list("name" = (analysed ? memorybank.effect.name : "Unknown Symptom"), "stage" = memorybank.effect.stage) - if (species_buffer) + data["species_buffer"] = null + if(species_buffer) data["species_buffer"] = analysed ? jointext(species_buffer, ", ") : "Unknown Species" - if (splicing) + data["effects"] = null + data["info"] = null + data["growth"] = 0 + data["affected_species"] = null + data["busy"] = null + if(splicing) data["busy"] = "Splicing..." - else if (scanning) + else if(scanning) data["busy"] = "Scanning..." - else if (burning) + else if(burning) data["busy"] = "Copying data to disk..." - else if (dish) + else if(dish) data["growth"] = min(dish.growth, 100) - if (dish.virus2) - if (dish.virus2.affected_species) - data["affected_species"] = dish.analysed ? jointext(dish.virus2.affected_species, ", ") : "Unknown" + if(dish.virus2) + if(dish.virus2.affected_species) + data["affected_species"] = dish.analysed ? dish.virus2.affected_species : list() - if (dish.growth >= 50) + if(dish.growth >= 50) var/list/effects[0] for (var/datum/disease2/effectholder/e in dish.virus2.effects) effects.Add(list(list("name" = (dish.analysed ? e.effect.name : "Unknown"), "stage" = (e.stage), "reference" = "\ref[e]"))) @@ -81,11 +91,7 @@ else data["info"] = "No dish loaded." - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "disease_splicer.tmpl", src.name, 400, 600) - ui.set_initial_data(data) - ui.open() + return data /obj/machinery/computer/diseasesplicer/process() if(stat & (NOPOWER|BROKEN)) @@ -95,100 +101,94 @@ scanning -= 1 if(!scanning) ping("\The [src] pings, \"Analysis complete.\"") - SSnanoui.update_uis(src) + SStgui.update_uis(src) if(splicing) splicing -= 1 if(!splicing) ping("\The [src] pings, \"Splicing operation complete.\"") - SSnanoui.update_uis(src) + SStgui.update_uis(src) if(burning) burning -= 1 if(!burning) var/obj/item/weapon/diseasedisk/d = new /obj/item/weapon/diseasedisk(src.loc) d.analysed = analysed if(analysed) - if (memorybank) + if(memorybank) d.name = "[memorybank.effect.name] GNA disk (Stage: [memorybank.effect.stage])" d.effect = memorybank - else if (species_buffer) + else if(species_buffer) d.name = "[jointext(species_buffer, ", ")] GNA disk" d.species = species_buffer else - if (memorybank) + if(memorybank) d.name = "Unknown GNA disk (Stage: [memorybank.effect.stage])" d.effect = memorybank - else if (species_buffer) + else if(species_buffer) d.name = "Unknown Species GNA disk" d.species = species_buffer ping("\The [src] pings, \"Backup disk saved.\"") - SSnanoui.update_uis(src) + SStgui.update_uis(src) -/obj/machinery/computer/diseasesplicer/Topic(href, href_list) - if(..()) return 1 +/obj/machinery/computer/diseasesplicer/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE var/mob/user = usr - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") + add_fingerprint(user) - src.add_fingerprint(user) + switch(action) + if("grab") + if(dish) + memorybank = locate(params["grab"]) + species_buffer = null + analysed = dish.analysed + dish = null + scanning = 10 + . = TRUE - if (href_list["close"]) - user.unset_machine() - ui.close() - return 0 + if("affected_species") + if(dish) + memorybank = null + species_buffer = dish.virus2.affected_species + analysed = dish.analysed + dish = null + scanning = 10 + . = TRUE - if (href_list["grab"]) - if (dish) - memorybank = locate(href_list["grab"]) - species_buffer = null - analysed = dish.analysed - dish = null - scanning = 10 - return 1 + if("eject") + if(dish) + dish.loc = src.loc + dish = null + . = TRUE - if (href_list["affected_species"]) - if (dish) - memorybank = null - species_buffer = dish.virus2.affected_species - analysed = dish.analysed - dish = null - scanning = 10 - return 1 + if("splice") + if(dish) + var/target = text2num(params["splice"]) // target = 1 to 4 for effects, 5 for species + if(memorybank && 0 < target && target <= 4) + if(target < memorybank.effect.stage) return // too powerful, catching this for href exploit prevention - if(href_list["eject"]) - if (dish) - dish.loc = src.loc - dish = null - return 1 + var/datum/disease2/effectholder/target_holder + var/list/illegal_types = list() + for(var/datum/disease2/effectholder/e in dish.virus2.effects) + if(e.stage == target) + target_holder = e + else + illegal_types += e.effect.type + if(memorybank.effect.type in illegal_types) return + target_holder.effect = memorybank.effect - if(href_list["splice"]) - if(dish) - var/target = text2num(href_list["splice"]) // target = 1 to 4 for effects, 5 for species - if(memorybank && 0 < target && target <= 4) - if(target < memorybank.effect.stage) return // too powerful, catching this for href exploit prevention + else if(species_buffer && target == 5) + dish.virus2.affected_species = species_buffer - var/datum/disease2/effectholder/target_holder - var/list/illegal_types = list() - for(var/datum/disease2/effectholder/e in dish.virus2.effects) - if(e.stage == target) - target_holder = e - else - illegal_types += e.effect.type - if(memorybank.effect.type in illegal_types) return - target_holder.effect = memorybank.effect + else + return - else if(species_buffer && target == 5) - dish.virus2.affected_species = species_buffer + splicing = 10 + dish.virus2.uniqueID = rand(0,10000) + . = TRUE - else - return + if("disk") + burning = 10 + . = TRUE - splicing = 10 - dish.virus2.uniqueID = rand(0,10000) - return 1 - - if(href_list["disk"]) - burning = 10 - return 1 - - return 0 diff --git a/code/modules/virus2/dishincubator.dm b/code/modules/virus2/dishincubator.dm index 15638718a4..9dd935247a 100644 --- a/code/modules/virus2/dishincubator.dm +++ b/code/modules/virus2/dishincubator.dm @@ -30,7 +30,7 @@ O.loc = src user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") - SSnanoui.update_uis(src) + SStgui.update_uis(src) src.attack_hand(user) return @@ -46,17 +46,23 @@ O.loc = src user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") - SSnanoui.update_uis(src) + SStgui.update_uis(src) src.attack_hand(user) /obj/machinery/disease2/incubator/attack_hand(mob/user as mob) - if(stat & (NOPOWER|BROKEN)) return - ui_interact(user) + if(stat & (NOPOWER|BROKEN)) + return + tgui_interact(user) -/obj/machinery/disease2/incubator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/disease2/incubator/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "DishIncubator", name) + ui.set_autoupdate(FALSE) + ui.open() +/obj/machinery/disease2/incubator/tgui_data(mob/user) var/data[0] data["chemicals_inserted"] = !!beaker data["dish_inserted"] = !!dish @@ -74,23 +80,19 @@ data["can_breed_virus"] = null data["blood_already_infected"] = null - if (beaker) + if(beaker) var/datum/reagent/blood/B = locate(/datum/reagent/blood) in beaker.reagents.reagent_list data["can_breed_virus"] = dish && dish.virus2 && B - if (B) - if (!B.data["virus2"]) + if(B) + if(!B.data["virus2"]) B.data["virus2"] = list() var/list/virus = B.data["virus2"] for (var/ID in virus) data["blood_already_infected"] = virus[ID] - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "dish_incubator.tmpl", src.name, 400, 600) - ui.set_initial_data(data) - ui.open() + return data /obj/machinery/disease2/incubator/process() if(dish && on && dish.virus2) @@ -105,7 +107,7 @@ foodsupply -= 1 dish.growth += 3 - SSnanoui.update_uis(src) + SStgui.update_uis(src) if(radiation) if(radiation > 50 & prob(5)) @@ -118,90 +120,82 @@ else if(prob(5)) dish.virus2.minormutate() radiation -= 1 - SSnanoui.update_uis(src) + SStgui.update_uis(src) if(toxins && prob(5)) dish.virus2.infectionchance -= 1 - SSnanoui.update_uis(src) + SStgui.update_uis(src) if(toxins > 50) dish.growth = 0 dish.virus2 = null - SSnanoui.update_uis(src) + SStgui.update_uis(src) else if(!dish) on = 0 icon_state = "incubator" - SSnanoui.update_uis(src) + SStgui.update_uis(src) if(beaker) if(foodsupply < 100 && beaker.reagents.remove_reagent("virusfood",5)) if(foodsupply + 10 <= 100) foodsupply += 10 - SSnanoui.update_uis(src) + SStgui.update_uis(src) - if (locate(/datum/reagent/toxin) in beaker.reagents.reagent_list && toxins < 100) + if(locate(/datum/reagent/toxin) in beaker.reagents.reagent_list && toxins < 100) for(var/datum/reagent/toxin/T in beaker.reagents.reagent_list) toxins += max(T.strength,1) beaker.reagents.remove_reagent(T.id,1) if(toxins > 100) toxins = 100 break - SSnanoui.update_uis(src) + SStgui.update_uis(src) -/obj/machinery/disease2/incubator/Topic(href, href_list) - if (..()) return 1 +/obj/machinery/disease2/incubator/tgui_act(action, params) + if(..()) + return TRUE var/mob/user = usr - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") + add_fingerprint(user) + switch(action) + if("ejectchem") + if(beaker) + beaker.loc = src.loc + beaker = null + . = TRUE - src.add_fingerprint(user) + if("power") + if(dish) + on = !on + icon_state = on ? "incubator_on" : "incubator" + . = TRUE - if (href_list["close"]) - user.unset_machine() - ui.close() - return 0 + if("ejectdish") + if(dish) + dish.loc = src.loc + dish = null + . = TRUE - if (href_list["ejectchem"]) - if(beaker) - beaker.loc = src.loc - beaker = null - return 1 + if("rad") + radiation = min(100, radiation + 10) + . = TRUE - if (href_list["power"]) - if (dish) - on = !on - icon_state = on ? "incubator_on" : "incubator" - return 1 + if("flush") + radiation = 0 + toxins = 0 + foodsupply = 0 + . = TRUE - if (href_list["ejectdish"]) - if(dish) - dish.loc = src.loc - dish = null - return 1 + if("virus") + if(!dish) + return TRUE - if (href_list["rad"]) - radiation = min(100, radiation + 10) - return 1 + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in beaker.reagents.reagent_list + if(!B) + return TRUE - if (href_list["flush"]) - radiation = 0 - toxins = 0 - foodsupply = 0 - return 1 + if(!B.data["virus2"]) + B.data["virus2"] = list() - if(href_list["virus"]) - if (!dish) - return 1 + var/list/virus = list("[dish.virus2.uniqueID]" = dish.virus2.getcopy()) + B.data["virus2"] += virus - var/datum/reagent/blood/B = locate(/datum/reagent/blood) in beaker.reagents.reagent_list - if (!B) - return 1 - - if (!B.data["virus2"]) - B.data["virus2"] = list() - - var/list/virus = list("[dish.virus2.uniqueID]" = dish.virus2.getcopy()) - B.data["virus2"] += virus - - ping("\The [src] pings, \"Injection complete.\"") - return 1 - - return 0 + ping("\The [src] pings, \"Injection complete.\"") + . = TRUE diff --git a/code/modules/virus2/isolator.dm b/code/modules/virus2/isolator.dm index 2a6d39d230..ff5e6dbcfe 100644 --- a/code/modules/virus2/isolator.dm +++ b/code/modules/virus2/isolator.dm @@ -1,8 +1,3 @@ -// UI menu navigation -#define HOME "home" -#define LIST "list" -#define ENTRY "entry" - /obj/machinery/disease2/isolator/ name = "pathogenic isolator" desc = "Used to isolate and identify diseases, allowing for comparison with a remote database." @@ -11,9 +6,7 @@ icon = 'icons/obj/virology_vr.dmi' //VOREStation Edit icon_state = "isolator" var/isolating = 0 - var/state = HOME var/datum/disease2/disease/virus2 = null - var/datum/data/record/entry = null var/obj/item/weapon/reagent_containers/syringe/sample = null /obj/machinery/disease2/isolator/update_icon() @@ -44,71 +37,57 @@ S.loc = src user.visible_message("[user] adds \a [O] to \the [src]!", "You add \a [O] to \the [src]!") - SSnanoui.update_uis(src) + SStgui.update_uis(src) update_icon() src.attack_hand(user) /obj/machinery/disease2/isolator/attack_hand(mob/user as mob) - if(stat & (NOPOWER|BROKEN)) return - ui_interact(user) + if(stat & (NOPOWER|BROKEN)) + return + tgui_interact(user) -/obj/machinery/disease2/isolator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/disease2/isolator/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PathogenicIsolator", name) + ui.open() - var/data[0] + +/obj/machinery/disease2/isolator/tgui_data(mob/user) + var/list/data = list() data["syringe_inserted"] = !!sample data["isolating"] = isolating data["pathogen_pool"] = null - data["state"] = state - data["entry"] = entry - data["can_print"] = (state != HOME || sample) && !isolating + data["can_print"] = !isolating - switch (state) - if (HOME) - if (sample) - var/list/pathogen_pool[0] - for(var/datum/reagent/blood/B in sample.reagents.reagent_list) - var/list/virus = B.data["virus2"] - for (var/ID in virus) - var/datum/disease2/disease/V = virus[ID] - var/datum/data/record/R = null - if (ID in virusDB) - R = virusDB[ID] + var/list/pathogen_pool = list() + if(sample) + for(var/datum/reagent/blood/B in sample.reagents.reagent_list) + var/list/virus = B.data["virus2"] + for (var/ID in virus) + var/datum/disease2/disease/V = virus[ID] + var/datum/data/record/R = null + if (ID in virusDB) + R = virusDB[ID] - var/mob/living/carbon/human/D = B.data["donor"] - pathogen_pool.Add(list(list(\ - "name" = "[D.get_species()] [B.name]", \ - "dna" = B.data["blood_DNA"], \ - "unique_id" = V.uniqueID, \ - "reference" = "\ref[V]", \ - "is_in_database" = !!R, \ - "record" = "\ref[R]"))) + var/mob/living/carbon/human/D = B.data["donor"] + pathogen_pool.Add(list(list(\ + "name" = "[D.get_species()] [B.name]", \ + "dna" = B.data["blood_DNA"], \ + "unique_id" = V.uniqueID, \ + "reference" = "\ref[V]", \ + "is_in_database" = !!R, \ + "record" = "\ref[R]"))) + data["pathogen_pool"] = pathogen_pool - if (pathogen_pool.len > 0) - data["pathogen_pool"] = pathogen_pool - - if (LIST) - var/list/db[0] - for (var/ID in virusDB) - var/datum/data/record/r = virusDB[ID] - db.Add(list(list("name" = r.fields["name"], "record" = "\ref[r]"))) - - if (db.len > 0) - data["database"] = db - - if (ENTRY) - if (entry) - var/desc = entry.fields["description"] - data["entry"] = list(\ - "name" = entry.fields["name"], \ - "description" = replacetext(desc, "\n", "")) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "pathogenic_isolator.tmpl", src.name, 400, 500) - ui.set_initial_data(data) - ui.open() + var/list/db = list() + for(var/ID in virusDB) + var/datum/data/record/r = virusDB[ID] + db.Add(list(list("name" = r.fields["name"], "record" = "\ref[r]"))) + data["database"] = db + data["modal"] = tgui_modal_data(src) + return data /obj/machinery/disease2/isolator/process() if (isolating > 0) @@ -120,62 +99,54 @@ virus2 = null ping("\The [src] pings, \"Viral strain isolated.\"") - SSnanoui.update_uis(src) + SStgui.update_uis(src) update_icon() -/obj/machinery/disease2/isolator/Topic(href, href_list) - if (..()) return 1 +/obj/machinery/disease2/isolator/tgui_act(action, list/params) + if(..()) + return TRUE var/mob/user = usr - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") + add_fingerprint(user) + + . = TRUE + switch(tgui_modal_act(src, action, params)) + if(TGUI_MODAL_ANSWER) + return - src.add_fingerprint(user) + switch(action) + if("view_entry") + var/datum/data/record/v = locate(params["vir"]) + if(!istype(v)) + return FALSE + tgui_modal_message(src, "virus", "", null, v.fields["tgui_description"]) + return TRUE - if (href_list["close"]) - user.unset_machine() - ui.close() - return 0 + if("print") + print(user, params) + return TRUE - if (href_list[HOME]) - state = HOME - return 1 + if("isolate") + var/datum/disease2/disease/V = locate(params["isolate"]) + if (V) + virus2 = V + isolating = 20 + update_icon() + return TRUE - if (href_list[LIST]) - state = LIST - return 1 - - if (href_list[ENTRY]) - if (istype(locate(href_list["view"]), /datum/data/record)) - entry = locate(href_list["view"]) - - state = ENTRY - return 1 - - if (href_list["print"]) - print(user) - return 1 - - if(!sample) return 1 - - if (href_list["isolate"]) - var/datum/disease2/disease/V = locate(href_list["isolate"]) - if (V) - virus2 = V - isolating = 20 + if("eject") + if(!sample) + return FALSE + sample.forceMove(loc) + sample = null update_icon() - return 1 + return TRUE - if (href_list["eject"]) - sample.loc = src.loc - sample = null - update_icon() - return 1 - -/obj/machinery/disease2/isolator/proc/print(var/mob/user) +/obj/machinery/disease2/isolator/proc/print(mob/user, list/params) var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc) - switch (state) - if (HOME) + switch(params["type"]) + if("patient_diagnosis") if (!sample) return P.name = "paper - Patient Diagnostic Report" P.info = {" @@ -207,7 +178,7 @@ Additional Notes:  "} - if (LIST) + if("virus_list") P.name = "paper - Virus List" P.info = {" [virology_letterhead("Virus List")] @@ -225,11 +196,14 @@ Additional Notes:  "} - if (ENTRY) + if("virus_record") + var/datum/data/record/v = locate(params["vir"]) + if(!istype(v)) + return FALSE P.name = "paper - Viral Profile" P.info = {" [virology_letterhead("Viral Profile")] - [entry.fields["description"]] + [v.fields["description"]]
Additional Notes:  "} diff --git a/html/changelogs/mechoid - mortiferin.yml b/html/changelogs/mechoid - mortiferin.yml new file mode 100644 index 0000000000..00ce2ca033 --- /dev/null +++ b/html/changelogs/mechoid - mortiferin.yml @@ -0,0 +1,37 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Mechoid + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Mortiferin added in place of old Necroxadone as a normal chem recipe." + - tweak: "Necroxadone changed to a more powerful alternative to Mortiferin which works even on corpses without bloodflow." diff --git a/html/font-awesome/css/all.min.css b/html/font-awesome/css/all.min.css index e7cdfffe75..a5e67e693d 100644 --- a/html/font-awesome/css/all.min.css +++ b/html/font-awesome/css/all.min.css @@ -1,5 +1,5 @@ /*! - * Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com + * Font Awesome Free 5.14.0 by @fontawesome - https://fontawesome.com * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) */ -.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(fa-regular-400.eot);src:url(fa-regular-400.eot?#iefix) format("embedded-opentype"),url(fa-regular-400.woff) format("woff")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(fa-solid-900.eot);src:url(fa-solid-900.eot?#iefix) format("embedded-opentype"),url(fa-solid-900.woff) format("woff")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file +.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(fa-regular-400.eot);src:url(fa-regular-400.eot?#iefix) format("embedded-opentype"),url(fa-regular-400.woff) format("woff")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(fa-solid-900.eot);src:url(fa-solid-900.eot?#iefix) format("embedded-opentype"),url(fa-solid-900.woff) format("woff")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/html/font-awesome/css/v4-shims.min.css b/html/font-awesome/css/v4-shims.min.css index 5f3fdc598c..ee29a2c92d 100644 --- a/html/font-awesome/css/v4-shims.min.css +++ b/html/font-awesome/css/v4-shims.min.css @@ -1,5 +1,5 @@ /*! - * Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com + * Font Awesome Free 5.14.0 by @fontawesome - https://fontawesome.com * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) */ -.fa.fa-glass:before{content:"\f000"}.fa.fa-meetup{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-star-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-o:before{content:"\f005"}.fa.fa-close:before,.fa.fa-remove:before{content:"\f00d"}.fa.fa-gear:before{content:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-trash-o:before{content:"\f2ed"}.fa.fa-file-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-o:before{content:"\f15b"}.fa.fa-clock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-clock-o:before{content:"\f017"}.fa.fa-arrow-circle-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:"\f358"}.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-play-circle-o:before{content:"\f144"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:"\f01e"}.fa.fa-refresh:before{content:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dedent:before{content:"\f03b"}.fa.fa-video-camera:before{content:"\f03d"}.fa.fa-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-picture-o:before{content:"\f03e"}.fa.fa-photo{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-photo:before{content:"\f03e"}.fa.fa-image{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-image:before{content:"\f03e"}.fa.fa-pencil:before{content:"\f303"}.fa.fa-map-marker:before{content:"\f3c5"}.fa.fa-pencil-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pencil-square-o:before{content:"\f044"}.fa.fa-share-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-share-square-o:before{content:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-square-o:before{content:"\f14a"}.fa.fa-arrows:before{content:"\f0b2"}.fa.fa-times-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-circle-o:before{content:"\f057"}.fa.fa-check-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-circle-o:before{content:"\f058"}.fa.fa-mail-forward:before{content:"\f064"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-warning:before{content:"\f071"}.fa.fa-calendar:before{content:"\f073"}.fa.fa-arrows-v:before{content:"\f338"}.fa.fa-arrows-h:before{content:"\f337"}.fa.fa-bar-chart{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart:before{content:"\f080"}.fa.fa-bar-chart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart-o:before{content:"\f080"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gears:before{content:"\f085"}.fa.fa-thumbs-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-up:before{content:"\f164"}.fa.fa-thumbs-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-down:before{content:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-heart-o:before{content:"\f004"}.fa.fa-sign-out:before{content:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin-square:before{content:"\f08c"}.fa.fa-thumb-tack:before{content:"\f08d"}.fa.fa-external-link:before{content:"\f35d"}.fa.fa-sign-in:before{content:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-lemon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lemon-o:before{content:"\f094"}.fa.fa-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-square-o:before{content:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bookmark-o:before{content:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook:before{content:"\f39e"}.fa.fa-facebook-f{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-f:before{content:"\f39e"}.fa.fa-github{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-feed:before{content:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hdd-o:before{content:"\f0a0"}.fa.fa-hand-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-right:before{content:"\f0a4"}.fa.fa-hand-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-left:before{content:"\f0a5"}.fa.fa-hand-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-up:before{content:"\f0a6"}.fa.fa-hand-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-down:before{content:"\f0a7"}.fa.fa-arrows-alt:before{content:"\f31e"}.fa.fa-group:before{content:"\f0c0"}.fa.fa-chain:before{content:"\f0c1"}.fa.fa-scissors:before{content:"\f0c4"}.fa.fa-files-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-files-o:before{content:"\f0c5"}.fa.fa-floppy-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-floppy-o:before{content:"\f0c7"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:"\f0c9"}.fa.fa-google-plus,.fa.fa-google-plus-square,.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus:before{content:"\f0d5"}.fa.fa-money{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-money:before{content:"\f3d1"}.fa.fa-unsorted:before{content:"\f0dc"}.fa.fa-sort-desc:before{content:"\f0dd"}.fa.fa-sort-asc:before{content:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin:before{content:"\f0e1"}.fa.fa-rotate-left:before{content:"\f0e2"}.fa.fa-legal:before{content:"\f0e3"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:"\f3fd"}.fa.fa-comment-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comment-o:before{content:"\f075"}.fa.fa-comments-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comments-o:before{content:"\f086"}.fa.fa-flash:before{content:"\f0e7"}.fa.fa-clipboard,.fa.fa-paste{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paste:before{content:"\f328"}.fa.fa-lightbulb-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lightbulb-o:before{content:"\f0eb"}.fa.fa-exchange:before{content:"\f362"}.fa.fa-cloud-download:before{content:"\f381"}.fa.fa-cloud-upload:before{content:"\f382"}.fa.fa-bell-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-o:before{content:"\f0f3"}.fa.fa-cutlery:before{content:"\f2e7"}.fa.fa-file-text-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-text-o:before{content:"\f15c"}.fa.fa-building-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-building-o:before{content:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hospital-o:before{content:"\f0f8"}.fa.fa-tablet:before{content:"\f3fa"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-o:before{content:"\f111"}.fa.fa-mail-reply:before{content:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-folder-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-o:before{content:"\f07b"}.fa.fa-folder-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-open-o:before{content:"\f07c"}.fa.fa-smile-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-smile-o:before{content:"\f118"}.fa.fa-frown-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-frown-o:before{content:"\f119"}.fa.fa-meh-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-meh-o:before{content:"\f11a"}.fa.fa-keyboard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-keyboard-o:before{content:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-flag-o:before{content:"\f024"}.fa.fa-mail-reply-all:before{content:"\f122"}.fa.fa-star-half-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-o:before{content:"\f089"}.fa.fa-star-half-empty{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-empty:before{content:"\f089"}.fa.fa-star-half-full{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-full:before{content:"\f089"}.fa.fa-code-fork:before{content:"\f126"}.fa.fa-chain-broken:before{content:"\f127"}.fa.fa-shield:before{content:"\f3ed"}.fa.fa-calendar-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-o:before{content:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ticket:before{content:"\f3ff"}.fa.fa-minus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-minus-square-o:before{content:"\f146"}.fa.fa-level-up:before{content:"\f3bf"}.fa.fa-level-down:before{content:"\f3be"}.fa.fa-pencil-square:before{content:"\f14b"}.fa.fa-external-link-square:before{content:"\f360"}.fa.fa-compass{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down:before{content:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-down:before{content:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-up:before{content:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-up:before{content:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-right:before{content:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-right:before{content:"\f152"}.fa.fa-eur:before,.fa.fa-euro:before{content:"\f153"}.fa.fa-gbp:before{content:"\f154"}.fa.fa-dollar:before,.fa.fa-usd:before{content:"\f155"}.fa.fa-inr:before,.fa.fa-rupee:before{content:"\f156"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:"\f157"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:"\f158"}.fa.fa-krw:before,.fa.fa-won:before{content:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitcoin:before{content:"\f15a"}.fa.fa-file-text:before{content:"\f15c"}.fa.fa-sort-alpha-asc:before{content:"\f15d"}.fa.fa-sort-alpha-desc:before{content:"\f15e"}.fa.fa-sort-amount-asc:before{content:"\f160"}.fa.fa-sort-amount-desc:before{content:"\f161"}.fa.fa-sort-numeric-asc:before{content:"\f162"}.fa.fa-sort-numeric-desc:before{content:"\f163"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-play,.fa.fa-youtube-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-youtube-play:before{content:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitbucket-square:before{content:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-long-arrow-down:before{content:"\f309"}.fa.fa-long-arrow-up:before{content:"\f30c"}.fa.fa-long-arrow-left:before{content:"\f30a"}.fa.fa-long-arrow-right:before{content:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gittip:before{content:"\f184"}.fa.fa-sun-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sun-o:before{content:"\f185"}.fa.fa-moon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-moon-o:before{content:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:"\f35a"}.fa.fa-arrow-circle-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-left:before{content:"\f191"}.fa.fa-toggle-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-left:before{content:"\f191"}.fa.fa-dot-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dot-circle-o:before{content:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:"\f195"}.fa.fa-plus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-plus-square-o:before{content:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:"\f19c"}.fa.fa-mortar-board:before{content:"\f19d"}.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-google,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle,.fa.fa-yahoo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-spoon:before{content:"\f2e5"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-steam,.fa.fa-steam-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-automobile:before{content:"\f1b9"}.fa.fa-cab:before{content:"\f1ba"}.fa.fa-envelope-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-o:before{content:"\f0e0"}.fa.fa-deviantart,.fa.fa-soundcloud{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-file-pdf-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-pdf-o:before{content:"\f1c1"}.fa.fa-file-word-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-word-o:before{content:"\f1c2"}.fa.fa-file-excel-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-excel-o:before{content:"\f1c3"}.fa.fa-file-powerpoint-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-powerpoint-o:before{content:"\f1c4"}.fa.fa-file-image-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-image-o:before{content:"\f1c5"}.fa.fa-file-photo-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-photo-o:before{content:"\f1c5"}.fa.fa-file-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-picture-o:before{content:"\f1c5"}.fa.fa-file-archive-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-archive-o:before{content:"\f1c6"}.fa.fa-file-zip-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-zip-o:before{content:"\f1c6"}.fa.fa-file-audio-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-audio-o:before{content:"\f1c7"}.fa.fa-file-sound-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-sound-o:before{content:"\f1c7"}.fa.fa-file-video-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-video-o:before{content:"\f1c8"}.fa.fa-file-movie-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-movie-o:before{content:"\f1c8"}.fa.fa-file-code-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-code-o:before{content:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-life-bouy,.fa.fa-life-ring{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-bouy:before{content:"\f1cd"}.fa.fa-life-buoy{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-buoy:before{content:"\f1cd"}.fa.fa-life-saver{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-saver:before{content:"\f1cd"}.fa.fa-support{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-support:before{content:"\f1cd"}.fa.fa-circle-o-notch:before{content:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ra:before{content:"\f1d0"}.fa.fa-resistance{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-resistance:before{content:"\f1d0"}.fa.fa-empire,.fa.fa-ge{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ge:before{content:"\f1d1"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-y-combinator-square:before{content:"\f1d4"}.fa.fa-yc-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc-square:before{content:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wechat:before{content:"\f1d7"}.fa.fa-send:before{content:"\f1d8"}.fa.fa-paper-plane-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paper-plane-o:before{content:"\f1d8"}.fa.fa-send-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-send-o:before{content:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-thin:before{content:"\f111"}.fa.fa-header:before{content:"\f1dc"}.fa.fa-sliders:before{content:"\f1de"}.fa.fa-futbol-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-futbol-o:before{content:"\f1e3"}.fa.fa-soccer-ball-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-soccer-ball-o:before{content:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-newspaper-o:before{content:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-slash-o:before{content:"\f1f6"}.fa.fa-trash:before{content:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-eyedropper:before{content:"\f1fb"}.fa.fa-area-chart:before{content:"\f1fe"}.fa.fa-pie-chart:before{content:"\f200"}.fa.fa-line-chart:before{content:"\f201"}.fa.fa-angellist,.fa.fa-ioxhost,.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-cc:before{content:"\f20a"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:"\f20b"}.fa.fa-meanpath{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-meanpath:before{content:"\f2b4"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-diamond:before{content:"\f3a5"}.fa.fa-intersex:before{content:"\f224"}.fa.fa-facebook-official{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-official:before{content:"\f09a"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-hotel:before{content:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc:before{content:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:"\f240"}.fa.fa-battery-3:before{content:"\f241"}.fa.fa-battery-2:before{content:"\f242"}.fa.fa-battery-1:before{content:"\f243"}.fa.fa-battery-0:before{content:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sticky-note-o:before{content:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-clone,.fa.fa-hourglass-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hourglass-o:before{content:"\f254"}.fa.fa-hourglass-1:before{content:"\f251"}.fa.fa-hourglass-2:before{content:"\f252"}.fa.fa-hourglass-3:before{content:"\f253"}.fa.fa-hand-rock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-rock-o:before{content:"\f255"}.fa.fa-hand-grab-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-grab-o:before{content:"\f255"}.fa.fa-hand-paper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-paper-o:before{content:"\f256"}.fa.fa-hand-stop-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-stop-o:before{content:"\f256"}.fa.fa-hand-scissors-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-scissors-o:before{content:"\f257"}.fa.fa-hand-lizard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-lizard-o:before{content:"\f258"}.fa.fa-hand-spock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-spock-o:before{content:"\f259"}.fa.fa-hand-pointer-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-pointer-o:before{content:"\f25a"}.fa.fa-hand-peace-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-peace-o:before{content:"\f25b"}.fa.fa-registered{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-chrome,.fa.fa-creative-commons,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-internet-explorer,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square,.fa.fa-opera,.fa.fa-safari,.fa.fa-tripadvisor,.fa.fa-wikipedia-w{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-television:before{content:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-calendar-plus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-plus-o:before{content:"\f271"}.fa.fa-calendar-minus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-minus-o:before{content:"\f272"}.fa.fa-calendar-times-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-times-o:before{content:"\f273"}.fa.fa-calendar-check-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-check-o:before{content:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-map-o:before{content:"\f279"}.fa.fa-commenting:before{content:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-commenting-o:before{content:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-vimeo:before{content:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card-alt:before{content:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-pause-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pause-circle-o:before{content:"\f28b"}.fa.fa-stop-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-stop-circle-o:before{content:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wheelchair-alt:before{content:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-question-circle-o:before{content:"\f059"}.fa.fa-volume-control-phone:before{content:"\f2a0"}.fa.fa-asl-interpreting:before{content:"\f2a3"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-signing:before{content:"\f2a7"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat,.fa.fa-snapchat-ghost,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-viadeo,.fa.fa-viadeo-square,.fa.fa-yoast{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-official:before{content:"\f2b3"}.fa.fa-google-plus-circle{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-circle:before{content:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-fa:before{content:"\f2b4"}.fa.fa-handshake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-handshake-o:before{content:"\f2b5"}.fa.fa-envelope-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-open-o:before{content:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-book-o:before{content:"\f2b9"}.fa.fa-vcard:before{content:"\f2bb"}.fa.fa-address-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-card-o:before{content:"\f2bb"}.fa.fa-vcard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-vcard-o:before{content:"\f2bb"}.fa.fa-user-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-circle-o:before{content:"\f2bd"}.fa.fa-user-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-o:before{content:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license:before{content:"\f2c2"}.fa.fa-id-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-id-card-o:before{content:"\f2c2"}.fa.fa-drivers-license-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license-o:before{content:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:"\f2c7"}.fa.fa-thermometer-3:before{content:"\f2c8"}.fa.fa-thermometer-2:before{content:"\f2c9"}.fa.fa-thermometer-1:before{content:"\f2ca"}.fa.fa-thermometer-0:before{content:"\f2cb"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle:before{content:"\f410"}.fa.fa-window-close-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-window-close-o:before{content:"\f410"}.fa.fa-times-rectangle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle-o:before{content:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-eercast:before{content:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-snowflake-o:before{content:"\f2dc"}.fa.fa-spotify,.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 5 Brands";font-weight:400} \ No newline at end of file +.fa.fa-glass:before{content:"\f000"}.fa.fa-meetup{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-star-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-o:before{content:"\f005"}.fa.fa-close:before,.fa.fa-remove:before{content:"\f00d"}.fa.fa-gear:before{content:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-trash-o:before{content:"\f2ed"}.fa.fa-file-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-o:before{content:"\f15b"}.fa.fa-clock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-clock-o:before{content:"\f017"}.fa.fa-arrow-circle-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:"\f358"}.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-play-circle-o:before{content:"\f144"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:"\f01e"}.fa.fa-refresh:before{content:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dedent:before{content:"\f03b"}.fa.fa-video-camera:before{content:"\f03d"}.fa.fa-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-picture-o:before{content:"\f03e"}.fa.fa-photo{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-photo:before{content:"\f03e"}.fa.fa-image{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-image:before{content:"\f03e"}.fa.fa-pencil:before{content:"\f303"}.fa.fa-map-marker:before{content:"\f3c5"}.fa.fa-pencil-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pencil-square-o:before{content:"\f044"}.fa.fa-share-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-share-square-o:before{content:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-square-o:before{content:"\f14a"}.fa.fa-arrows:before{content:"\f0b2"}.fa.fa-times-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-circle-o:before{content:"\f057"}.fa.fa-check-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-circle-o:before{content:"\f058"}.fa.fa-mail-forward:before{content:"\f064"}.fa.fa-expand:before{content:"\f424"}.fa.fa-compress:before{content:"\f422"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-warning:before{content:"\f071"}.fa.fa-calendar:before{content:"\f073"}.fa.fa-arrows-v:before{content:"\f338"}.fa.fa-arrows-h:before{content:"\f337"}.fa.fa-bar-chart{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart:before{content:"\f080"}.fa.fa-bar-chart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart-o:before{content:"\f080"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gears:before{content:"\f085"}.fa.fa-thumbs-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-up:before{content:"\f164"}.fa.fa-thumbs-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-down:before{content:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-heart-o:before{content:"\f004"}.fa.fa-sign-out:before{content:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin-square:before{content:"\f08c"}.fa.fa-thumb-tack:before{content:"\f08d"}.fa.fa-external-link:before{content:"\f35d"}.fa.fa-sign-in:before{content:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-lemon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lemon-o:before{content:"\f094"}.fa.fa-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-square-o:before{content:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bookmark-o:before{content:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook:before{content:"\f39e"}.fa.fa-facebook-f{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-f:before{content:"\f39e"}.fa.fa-github{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-feed:before{content:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hdd-o:before{content:"\f0a0"}.fa.fa-hand-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-right:before{content:"\f0a4"}.fa.fa-hand-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-left:before{content:"\f0a5"}.fa.fa-hand-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-up:before{content:"\f0a6"}.fa.fa-hand-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-down:before{content:"\f0a7"}.fa.fa-arrows-alt:before{content:"\f31e"}.fa.fa-group:before{content:"\f0c0"}.fa.fa-chain:before{content:"\f0c1"}.fa.fa-scissors:before{content:"\f0c4"}.fa.fa-files-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-files-o:before{content:"\f0c5"}.fa.fa-floppy-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-floppy-o:before{content:"\f0c7"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:"\f0c9"}.fa.fa-google-plus,.fa.fa-google-plus-square,.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus:before{content:"\f0d5"}.fa.fa-money{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-money:before{content:"\f3d1"}.fa.fa-unsorted:before{content:"\f0dc"}.fa.fa-sort-desc:before{content:"\f0dd"}.fa.fa-sort-asc:before{content:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin:before{content:"\f0e1"}.fa.fa-rotate-left:before{content:"\f0e2"}.fa.fa-legal:before{content:"\f0e3"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:"\f3fd"}.fa.fa-comment-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comment-o:before{content:"\f075"}.fa.fa-comments-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comments-o:before{content:"\f086"}.fa.fa-flash:before{content:"\f0e7"}.fa.fa-clipboard,.fa.fa-paste{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paste:before{content:"\f328"}.fa.fa-lightbulb-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lightbulb-o:before{content:"\f0eb"}.fa.fa-exchange:before{content:"\f362"}.fa.fa-cloud-download:before{content:"\f381"}.fa.fa-cloud-upload:before{content:"\f382"}.fa.fa-bell-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-o:before{content:"\f0f3"}.fa.fa-cutlery:before{content:"\f2e7"}.fa.fa-file-text-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-text-o:before{content:"\f15c"}.fa.fa-building-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-building-o:before{content:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hospital-o:before{content:"\f0f8"}.fa.fa-tablet:before{content:"\f3fa"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-o:before{content:"\f111"}.fa.fa-mail-reply:before{content:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-folder-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-o:before{content:"\f07b"}.fa.fa-folder-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-open-o:before{content:"\f07c"}.fa.fa-smile-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-smile-o:before{content:"\f118"}.fa.fa-frown-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-frown-o:before{content:"\f119"}.fa.fa-meh-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-meh-o:before{content:"\f11a"}.fa.fa-keyboard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-keyboard-o:before{content:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-flag-o:before{content:"\f024"}.fa.fa-mail-reply-all:before{content:"\f122"}.fa.fa-star-half-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-o:before{content:"\f089"}.fa.fa-star-half-empty{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-empty:before{content:"\f089"}.fa.fa-star-half-full{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-full:before{content:"\f089"}.fa.fa-code-fork:before{content:"\f126"}.fa.fa-chain-broken:before{content:"\f127"}.fa.fa-shield:before{content:"\f3ed"}.fa.fa-calendar-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-o:before{content:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ticket:before{content:"\f3ff"}.fa.fa-minus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-minus-square-o:before{content:"\f146"}.fa.fa-level-up:before{content:"\f3bf"}.fa.fa-level-down:before{content:"\f3be"}.fa.fa-pencil-square:before{content:"\f14b"}.fa.fa-external-link-square:before{content:"\f360"}.fa.fa-compass{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down:before{content:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-down:before{content:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-up:before{content:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-up:before{content:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-right:before{content:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-right:before{content:"\f152"}.fa.fa-eur:before,.fa.fa-euro:before{content:"\f153"}.fa.fa-gbp:before{content:"\f154"}.fa.fa-dollar:before,.fa.fa-usd:before{content:"\f155"}.fa.fa-inr:before,.fa.fa-rupee:before{content:"\f156"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:"\f157"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:"\f158"}.fa.fa-krw:before,.fa.fa-won:before{content:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitcoin:before{content:"\f15a"}.fa.fa-file-text:before{content:"\f15c"}.fa.fa-sort-alpha-asc:before{content:"\f15d"}.fa.fa-sort-alpha-desc:before{content:"\f881"}.fa.fa-sort-amount-asc:before{content:"\f160"}.fa.fa-sort-amount-desc:before{content:"\f884"}.fa.fa-sort-numeric-asc:before{content:"\f162"}.fa.fa-sort-numeric-desc:before{content:"\f886"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-play,.fa.fa-youtube-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-youtube-play:before{content:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitbucket-square:before{content:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-long-arrow-down:before{content:"\f309"}.fa.fa-long-arrow-up:before{content:"\f30c"}.fa.fa-long-arrow-left:before{content:"\f30a"}.fa.fa-long-arrow-right:before{content:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gittip:before{content:"\f184"}.fa.fa-sun-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sun-o:before{content:"\f185"}.fa.fa-moon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-moon-o:before{content:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:"\f35a"}.fa.fa-arrow-circle-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-left:before{content:"\f191"}.fa.fa-toggle-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-left:before{content:"\f191"}.fa.fa-dot-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dot-circle-o:before{content:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:"\f195"}.fa.fa-plus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-plus-square-o:before{content:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:"\f19c"}.fa.fa-mortar-board:before{content:"\f19d"}.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-google,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle,.fa.fa-yahoo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-spoon:before{content:"\f2e5"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-steam,.fa.fa-steam-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-automobile:before{content:"\f1b9"}.fa.fa-envelope-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-o:before{content:"\f0e0"}.fa.fa-deviantart,.fa.fa-soundcloud,.fa.fa-spotify{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-file-pdf-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-pdf-o:before{content:"\f1c1"}.fa.fa-file-word-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-word-o:before{content:"\f1c2"}.fa.fa-file-excel-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-excel-o:before{content:"\f1c3"}.fa.fa-file-powerpoint-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-powerpoint-o:before{content:"\f1c4"}.fa.fa-file-image-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-image-o:before{content:"\f1c5"}.fa.fa-file-photo-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-photo-o:before{content:"\f1c5"}.fa.fa-file-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-picture-o:before{content:"\f1c5"}.fa.fa-file-archive-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-archive-o:before{content:"\f1c6"}.fa.fa-file-zip-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-zip-o:before{content:"\f1c6"}.fa.fa-file-audio-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-audio-o:before{content:"\f1c7"}.fa.fa-file-sound-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-sound-o:before{content:"\f1c7"}.fa.fa-file-video-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-video-o:before{content:"\f1c8"}.fa.fa-file-movie-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-movie-o:before{content:"\f1c8"}.fa.fa-file-code-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-code-o:before{content:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-life-bouy,.fa.fa-life-ring{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-bouy:before{content:"\f1cd"}.fa.fa-life-buoy{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-buoy:before{content:"\f1cd"}.fa.fa-life-saver{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-saver:before{content:"\f1cd"}.fa.fa-support{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-support:before{content:"\f1cd"}.fa.fa-circle-o-notch:before{content:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ra:before{content:"\f1d0"}.fa.fa-resistance{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-resistance:before{content:"\f1d0"}.fa.fa-empire,.fa.fa-ge{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ge:before{content:"\f1d1"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-y-combinator-square:before{content:"\f1d4"}.fa.fa-yc-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc-square:before{content:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wechat:before{content:"\f1d7"}.fa.fa-send:before{content:"\f1d8"}.fa.fa-paper-plane-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paper-plane-o:before{content:"\f1d8"}.fa.fa-send-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-send-o:before{content:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-thin:before{content:"\f111"}.fa.fa-header:before{content:"\f1dc"}.fa.fa-sliders:before{content:"\f1de"}.fa.fa-futbol-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-futbol-o:before{content:"\f1e3"}.fa.fa-soccer-ball-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-soccer-ball-o:before{content:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-newspaper-o:before{content:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-slash-o:before{content:"\f1f6"}.fa.fa-trash:before{content:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-eyedropper:before{content:"\f1fb"}.fa.fa-area-chart:before{content:"\f1fe"}.fa.fa-pie-chart:before{content:"\f200"}.fa.fa-line-chart:before{content:"\f201"}.fa.fa-angellist,.fa.fa-ioxhost,.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-cc:before{content:"\f20a"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:"\f20b"}.fa.fa-meanpath{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-meanpath:before{content:"\f2b4"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-diamond:before{content:"\f3a5"}.fa.fa-intersex:before{content:"\f224"}.fa.fa-facebook-official{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-official:before{content:"\f09a"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-hotel:before{content:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc:before{content:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:"\f240"}.fa.fa-battery-3:before{content:"\f241"}.fa.fa-battery-2:before{content:"\f242"}.fa.fa-battery-1:before{content:"\f243"}.fa.fa-battery-0:before{content:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sticky-note-o:before{content:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-clone,.fa.fa-hourglass-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hourglass-o:before{content:"\f254"}.fa.fa-hourglass-1:before{content:"\f251"}.fa.fa-hourglass-2:before{content:"\f252"}.fa.fa-hourglass-3:before{content:"\f253"}.fa.fa-hand-rock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-rock-o:before{content:"\f255"}.fa.fa-hand-grab-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-grab-o:before{content:"\f255"}.fa.fa-hand-paper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-paper-o:before{content:"\f256"}.fa.fa-hand-stop-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-stop-o:before{content:"\f256"}.fa.fa-hand-scissors-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-scissors-o:before{content:"\f257"}.fa.fa-hand-lizard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-lizard-o:before{content:"\f258"}.fa.fa-hand-spock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-spock-o:before{content:"\f259"}.fa.fa-hand-pointer-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-pointer-o:before{content:"\f25a"}.fa.fa-hand-peace-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-peace-o:before{content:"\f25b"}.fa.fa-registered{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-chrome,.fa.fa-creative-commons,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-internet-explorer,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square,.fa.fa-opera,.fa.fa-safari,.fa.fa-tripadvisor,.fa.fa-wikipedia-w{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-television:before{content:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-calendar-plus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-plus-o:before{content:"\f271"}.fa.fa-calendar-minus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-minus-o:before{content:"\f272"}.fa.fa-calendar-times-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-times-o:before{content:"\f273"}.fa.fa-calendar-check-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-check-o:before{content:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-map-o:before{content:"\f279"}.fa.fa-commenting:before{content:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-commenting-o:before{content:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-vimeo:before{content:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card-alt:before{content:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-pause-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pause-circle-o:before{content:"\f28b"}.fa.fa-stop-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-stop-circle-o:before{content:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wheelchair-alt:before{content:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-question-circle-o:before{content:"\f059"}.fa.fa-volume-control-phone:before{content:"\f2a0"}.fa.fa-asl-interpreting:before{content:"\f2a3"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-signing:before{content:"\f2a7"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat,.fa.fa-snapchat-ghost,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-viadeo,.fa.fa-viadeo-square,.fa.fa-yoast{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-official:before{content:"\f2b3"}.fa.fa-google-plus-circle{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-circle:before{content:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-fa:before{content:"\f2b4"}.fa.fa-handshake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-handshake-o:before{content:"\f2b5"}.fa.fa-envelope-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-open-o:before{content:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-book-o:before{content:"\f2b9"}.fa.fa-vcard:before{content:"\f2bb"}.fa.fa-address-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-card-o:before{content:"\f2bb"}.fa.fa-vcard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-vcard-o:before{content:"\f2bb"}.fa.fa-user-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-circle-o:before{content:"\f2bd"}.fa.fa-user-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-o:before{content:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license:before{content:"\f2c2"}.fa.fa-id-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-id-card-o:before{content:"\f2c2"}.fa.fa-drivers-license-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license-o:before{content:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:"\f2c7"}.fa.fa-thermometer-3:before{content:"\f2c8"}.fa.fa-thermometer-2:before{content:"\f2c9"}.fa.fa-thermometer-1:before{content:"\f2ca"}.fa.fa-thermometer-0:before{content:"\f2cb"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle:before{content:"\f410"}.fa.fa-window-close-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-window-close-o:before{content:"\f410"}.fa.fa-times-rectangle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle-o:before{content:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-eercast:before{content:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-snowflake-o:before{content:"\f2dc"}.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-cab:before{content:"\f1ba"} \ No newline at end of file diff --git a/html/font-awesome/webfonts/fa-regular-400.eot b/html/font-awesome/webfonts/fa-regular-400.eot index d62be2fad8..479b32cecc 100644 Binary files a/html/font-awesome/webfonts/fa-regular-400.eot and b/html/font-awesome/webfonts/fa-regular-400.eot differ diff --git a/html/font-awesome/webfonts/fa-regular-400.woff b/html/font-awesome/webfonts/fa-regular-400.woff index 43b1a9ae49..c390c60e2b 100644 Binary files a/html/font-awesome/webfonts/fa-regular-400.woff and b/html/font-awesome/webfonts/fa-regular-400.woff differ diff --git a/html/font-awesome/webfonts/fa-solid-900.eot b/html/font-awesome/webfonts/fa-solid-900.eot index c77baa8d46..52883b93c8 100644 Binary files a/html/font-awesome/webfonts/fa-solid-900.eot and b/html/font-awesome/webfonts/fa-solid-900.eot differ diff --git a/html/font-awesome/webfonts/fa-solid-900.woff b/html/font-awesome/webfonts/fa-solid-900.woff index 77c1786227..aff125d658 100644 Binary files a/html/font-awesome/webfonts/fa-solid-900.woff and b/html/font-awesome/webfonts/fa-solid-900.woff differ diff --git a/icons/mob/back_vr.dmi b/icons/mob/back_vr.dmi index 474731f1a1..21eb4cfdd2 100644 Binary files a/icons/mob/back_vr.dmi and b/icons/mob/back_vr.dmi differ diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index 0d607dd537..e6ef1ec7b5 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/human_face_m.dmi b/icons/mob/human_face_m.dmi index 9b5c1441eb..35c951ca60 100644 Binary files a/icons/mob/human_face_m.dmi and b/icons/mob/human_face_m.dmi differ diff --git a/icons/mob/species/seromi/belt.dmi b/icons/mob/species/seromi/belt.dmi index 19a4a78cd9..fa68573c10 100644 Binary files a/icons/mob/species/seromi/belt.dmi and b/icons/mob/species/seromi/belt.dmi differ diff --git a/icons/mob/species/seromi/ears.dmi b/icons/mob/species/seromi/ears.dmi index 8730afe6d0..fb2d0a13f5 100644 Binary files a/icons/mob/species/seromi/ears.dmi and b/icons/mob/species/seromi/ears.dmi differ diff --git a/icons/mob/species/seromi/head.dmi b/icons/mob/species/seromi/head.dmi index bd105df155..bf346475d3 100644 Binary files a/icons/mob/species/seromi/head.dmi and b/icons/mob/species/seromi/head.dmi differ diff --git a/icons/mob/species/seromi/suit.dmi b/icons/mob/species/seromi/suit.dmi index db3b58db74..638e79027a 100644 Binary files a/icons/mob/species/seromi/suit.dmi and b/icons/mob/species/seromi/suit.dmi differ diff --git a/icons/mob/species/seromi/teshari_uniform.dmi b/icons/mob/species/seromi/teshari_uniform.dmi index 17cbd1b567..627a03f201 100644 Binary files a/icons/mob/species/seromi/teshari_uniform.dmi and b/icons/mob/species/seromi/teshari_uniform.dmi differ diff --git a/icons/mob/species/seromi/ties.dmi b/icons/mob/species/seromi/ties.dmi index bd88c2dedd..ad23d77e2b 100644 Binary files a/icons/mob/species/seromi/ties.dmi and b/icons/mob/species/seromi/ties.dmi differ diff --git a/icons/mob/species/seromi/uniform.dmi b/icons/mob/species/seromi/uniform.dmi index c2122bd177..63acfcca49 100644 Binary files a/icons/mob/species/seromi/uniform.dmi and b/icons/mob/species/seromi/uniform.dmi differ diff --git a/icons/obj/clothing/species/seromi/uniform.dmi b/icons/obj/clothing/species/seromi/uniform.dmi index f2dc52a913..e1c6e2f464 100644 Binary files a/icons/obj/clothing/species/seromi/uniform.dmi and b/icons/obj/clothing/species/seromi/uniform.dmi differ diff --git a/icons/obj/clothing/ties.dmi b/icons/obj/clothing/ties.dmi index aa0df8a3b2..21d8bbff1d 100644 Binary files a/icons/obj/clothing/ties.dmi and b/icons/obj/clothing/ties.dmi differ diff --git a/icons/obj/curtain.dmi b/icons/obj/curtain.dmi index 69b7de1dc0..dcf4cf0bcd 100644 Binary files a/icons/obj/curtain.dmi and b/icons/obj/curtain.dmi differ diff --git a/icons/obj/drinks_vr.dmi b/icons/obj/drinks_vr.dmi index 4678928d48..0f383a823f 100644 Binary files a/icons/obj/drinks_vr.dmi and b/icons/obj/drinks_vr.dmi differ diff --git a/maps/southern_cross/southern_cross-8.dmm b/maps/southern_cross/southern_cross-8.dmm index 500cc9c393..cc706e9098 100644 --- a/maps/southern_cross/southern_cross-8.dmm +++ b/maps/southern_cross/southern_cross-8.dmm @@ -1,343 +1,343 @@ -"aa" = (/turf/unsimulated/wall/planetary/sif,/area/surface/outside/wilderness/mountains) -"ab" = (/turf/unsimulated/wall/planetary/sif{icon_state = "rock-dark"},/area/surface/outside/wilderness/mountains) -"ac" = (/turf/simulated/mineral/sif,/area/surface/outside/wilderness/mountains) -"ad" = (/obj/effect/zone_divider,/turf/simulated/mineral/sif,/area/surface/outside/wilderness/mountains) -"ae" = (/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outside/wilderness/deep) -"af" = (/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outpost/wall) -"ag" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outside/wilderness/deep) -"ah" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/wilderness/deep) -"ai" = (/turf/simulated/floor/outdoors/dirt,/area/surface/outside/wilderness/deep) -"aj" = (/turf/simulated/floor/outdoors/grass/sif/planetuse,/area/surface/outside/wilderness/deep) -"ak" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/grass/sif/planetuse,/area/surface/outside/wilderness/deep) -"al" = (/turf/unsimulated/wall/planetary/sif,/area/surface/outside/river/svartan) -"am" = (/turf/simulated/floor/water,/area/surface/outside/river/svartan) -"an" = (/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) -"ao" = (/turf/simulated/floor/outdoors/dirt,/area/surface/outside/path/wilderness) -"ap" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/wilderness/normal) -"aq" = (/turf/simulated/floor/plating/sif/planetuse,/area/surface/outside/path/wilderness) -"ar" = (/turf/simulated/floor/wood,/area/surface/outside/path/wilderness) -"as" = (/turf/simulated/wall/wood,/area/surface/outside/path/wilderness) -"at" = (/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outside/wilderness/normal) -"au" = (/obj/effect/step_trigger/teleporter/bridge/west_to_east,/obj/structure/railing{dir = 4},/turf/simulated/floor/water,/area/surface/outside/river/svartan) -"av" = (/obj/effect/step_trigger/teleporter/bridge/east_to_west,/obj/structure/railing{dir = 8},/turf/simulated/floor/water,/area/surface/outside/river/svartan) -"aw" = (/obj/effect/zone_divider,/turf/simulated/floor/water,/area/surface/outside/river/svartan) -"ax" = (/obj/effect/step_trigger/teleporter/bridge/east_to_west/small,/turf/simulated/floor/water,/area/surface/outside/river/svartan) -"ay" = (/obj/effect/step_trigger/teleporter/bridge/west_to_east,/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) -"az" = (/obj/effect/step_trigger/teleporter/bridge/east_to_west,/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) -"aA" = (/obj/effect/zone_divider,/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) -"aB" = (/obj/effect/step_trigger/teleporter/bridge/west_to_east/small,/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) -"aC" = (/obj/structure/showcase/sign{desc = "This appears to be a sign warning people that the other side is extremely hazardous."; icon_state = "wilderness2"; pixel_y = -5},/turf/simulated/wall/wood,/area/surface/outside/path/wilderness) -"aD" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outside/wilderness/normal) -"aE" = (/obj/effect/step_trigger/teleporter/bridge/west_to_east,/obj/structure/railing{dir = 4},/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) -"aF" = (/obj/effect/step_trigger/teleporter/bridge/east_to_west,/obj/structure/railing{dir = 8},/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) -"aG" = (/turf/simulated/floor/outdoors/grass/sif/planetuse,/area/surface/outside/wilderness/normal) -"aH" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/grass/sif/planetuse,/area/surface/outside/wilderness/normal) -"aI" = (/turf/simulated/floor/outdoors/dirt,/area/surface/outside/wilderness/normal) -"aJ" = (/turf/simulated/floor/outdoors/rocks/sif/planetuse,/area/surface/outside/wilderness/deep) -"aK" = (/turf/simulated/floor/water,/area/surface/outside/ocean) -"aL" = (/turf/unsimulated/wall/planetary/sif,/area/surface/outside/ocean) -"aM" = (/turf/simulated/floor/outdoors/rocks/sif/planetuse,/area/surface/outside/wilderness/normal) -"aN" = (/turf/simulated/floor/water/deep,/area/surface/outside/ocean) -"aO" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/wilderness/normal) -"aP" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/rocks/sif/planetuse,/area/surface/outside/wilderness/normal) -"aQ" = (/obj/effect/zone_divider,/turf/simulated/floor/water,/area/surface/outside/ocean) -"aR" = (/obj/effect/zone_divider,/turf/simulated/floor/water/deep,/area/surface/outside/ocean) -"aS" = (/turf/simulated/floor/wood{outdoors = 1},/area/surface/outside/path/wilderness) -"aT" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/shuttle/shuttle2/mining) -"aU" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/shuttle/shuttle1/mining) -"aV" = (/turf/simulated/floor/outdoors/grass/sif/planetuse{tree_chance = 0},/area/surface/outside/wilderness/normal) -"aW" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/path/wilderness) -"aX" = (/turf/simulated/floor/outdoors/grass/sif/planetuse{tree_chance = 0},/area/shuttle/shuttle2/mining) -"aY" = (/turf/simulated/floor/outdoors/grass/sif/planetuse{tree_chance = 0},/area/shuttle/shuttle1/mining) -"aZ" = (/obj/structure/grille,/obj/structure/window/reinforced/full,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"ba" = (/turf/simulated/wall/log_sif,/area/surface/outpost/shelter) -"bb" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/path/wilderness) -"bc" = (/obj/structure/simple_door/sifwood,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bd" = (/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/power/port_gen/pacman,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"be" = (/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bf" = (/obj/machinery/recharger/wallcharger{pixel_x = 4; pixel_y = 26},/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bg" = (/obj/structure/table/steel,/obj/machinery/power/apc{dir = 8; locked = 0; name = "west bump"; operating = 0; pixel_x = -24},/obj/structure/cable,/obj/item/stack/material/phoron,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bh" = (/obj/structure/bed/chair{dir = 8},/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bi" = (/obj/structure/closet,/obj/random/maintenance/clean,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bj" = (/obj/structure/table/steel,/obj/machinery/cell_charger,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bk" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/wilderness/mountains) -"bl" = (/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) -"bm" = (/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outside/path/wilderness) -"bn" = (/obj/item/weapon/banner/nt,/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outside/path/wilderness) -"bo" = (/turf/simulated/shuttle/wall/voidcraft/hard_corner,/area/surface/outpost/wall/checkpoint) -"bp" = (/obj/machinery/door/airlock/voidcraft{name = "Wilderness Containment"},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) -"bq" = (/turf/simulated/shuttle/wall/voidcraft,/area/surface/outpost/wall/checkpoint) -"br" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) -"bs" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) -"bt" = (/obj/item/weapon/banner/virgov,/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outside/path/wilderness) -"bu" = (/obj/effect/map_effect/portal/master/side_b/wilderness_to_caves{icon_state = "portal_side_b"; dir = 1},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) -"bv" = (/obj/structure/closet/crate,/obj/random/powercell,/obj/item/weapon/tool/screwdriver,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bw" = (/obj/random/junk,/obj/machinery/embedded_controller/radio/simple_docking_controller{frequency = 1380; id_tag = "mining_dock_1"; name = "shuttle bay controller"; pixel_x = 0; pixel_y = -26; tag_door = "mining_dock_1_door"},/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bx" = (/obj/item/weapon/banner/virgov,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"by" = (/obj/machinery/space_heater,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bz" = (/obj/machinery/space_heater,/obj/machinery/embedded_controller/radio/simple_docking_controller{frequency = 1380; id_tag = "mining_dock_2"; name = "shuttle bay controller"; pixel_x = 0; pixel_y = -26; tag_door = "mining_dock_2_door"},/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) -"bA" = (/obj/effect/shuttle_landmark{docking_controller = "mining_dock_2"; landmark_tag = "shuttle2_mining"; name = "Wilderness Landing Site"},/turf/simulated/floor/outdoors/grass/sif/planetuse{tree_chance = 0},/area/shuttle/shuttle2/mining) -"bB" = (/obj/effect/shuttle_landmark{docking_controller = "mining_dock_1"; landmark_tag = "shuttle1_mining"; name = "Wilderness Landing Site"},/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/shuttle/shuttle1/mining) -"bC" = (/obj/effect/map_effect/portal/line/side_b{icon_state = "portal_line_side_b"; dir = 1},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) -"bD" = (/obj/effect/map_effect/portal/line/side_b{icon_state = "portal_line_side_b"; dir = 1},/turf/simulated/floor/water,/area/surface/outside/ocean) -"bE" = (/obj/effect/map_effect/portal/master/side_b/wilderness_to_caves/river{icon_state = "portal_side_b"; dir = 1},/turf/simulated/floor/water,/area/surface/outside/ocean) -"bF" = (/obj/effect/map_effect/perma_light/concentrated/incandescent,/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) +"aa" = (/turf/unsimulated/wall/planetary/sif,/area/surface/outside/wilderness/mountains) +"ab" = (/turf/unsimulated/wall/planetary/sif{icon_state = "rock-dark"},/area/surface/outside/wilderness/mountains) +"ac" = (/turf/simulated/mineral/sif,/area/surface/outside/wilderness/mountains) +"ad" = (/obj/effect/zone_divider,/turf/simulated/mineral/sif,/area/surface/outside/wilderness/mountains) +"ae" = (/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outside/wilderness/deep) +"af" = (/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outpost/wall) +"ag" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outside/wilderness/deep) +"ah" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/wilderness/deep) +"ai" = (/turf/simulated/floor/outdoors/dirt,/area/surface/outside/wilderness/deep) +"aj" = (/turf/simulated/floor/outdoors/grass/sif/planetuse,/area/surface/outside/wilderness/deep) +"ak" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/grass/sif/planetuse,/area/surface/outside/wilderness/deep) +"al" = (/turf/unsimulated/wall/planetary/sif,/area/surface/outside/river/svartan) +"am" = (/turf/simulated/floor/water,/area/surface/outside/river/svartan) +"an" = (/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) +"ao" = (/turf/simulated/floor/outdoors/dirt,/area/surface/outside/path/wilderness) +"ap" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/wilderness/normal) +"aq" = (/turf/simulated/floor/plating/sif/planetuse,/area/surface/outside/path/wilderness) +"ar" = (/turf/simulated/floor/wood,/area/surface/outside/path/wilderness) +"as" = (/turf/simulated/wall/wood,/area/surface/outside/path/wilderness) +"at" = (/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outside/wilderness/normal) +"au" = (/obj/effect/step_trigger/teleporter/bridge/west_to_east,/obj/structure/railing{dir = 4},/turf/simulated/floor/water,/area/surface/outside/river/svartan) +"av" = (/obj/effect/step_trigger/teleporter/bridge/east_to_west,/obj/structure/railing{dir = 8},/turf/simulated/floor/water,/area/surface/outside/river/svartan) +"aw" = (/obj/effect/zone_divider,/turf/simulated/floor/water,/area/surface/outside/river/svartan) +"ax" = (/obj/effect/step_trigger/teleporter/bridge/east_to_west/small,/turf/simulated/floor/water,/area/surface/outside/river/svartan) +"ay" = (/obj/effect/step_trigger/teleporter/bridge/west_to_east,/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) +"az" = (/obj/effect/step_trigger/teleporter/bridge/east_to_west,/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) +"aA" = (/obj/effect/zone_divider,/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) +"aB" = (/obj/effect/step_trigger/teleporter/bridge/west_to_east/small,/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) +"aC" = (/obj/structure/showcase/sign{desc = "This appears to be a sign warning people that the other side is extremely hazardous."; icon_state = "wilderness2"; pixel_y = -5},/turf/simulated/wall/wood,/area/surface/outside/path/wilderness) +"aD" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/grass/sif/forest/planetuse,/area/surface/outside/wilderness/normal) +"aE" = (/obj/effect/step_trigger/teleporter/bridge/west_to_east,/obj/structure/railing{dir = 4},/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) +"aF" = (/obj/effect/step_trigger/teleporter/bridge/east_to_west,/obj/structure/railing{dir = 8},/turf/simulated/floor/water/deep,/area/surface/outside/river/svartan) +"aG" = (/turf/simulated/floor/outdoors/grass/sif/planetuse,/area/surface/outside/wilderness/normal) +"aH" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/grass/sif/planetuse,/area/surface/outside/wilderness/normal) +"aI" = (/turf/simulated/floor/outdoors/dirt,/area/surface/outside/wilderness/normal) +"aJ" = (/turf/simulated/floor/outdoors/rocks/sif/planetuse,/area/surface/outside/wilderness/deep) +"aK" = (/turf/simulated/floor/water,/area/surface/outside/ocean) +"aL" = (/turf/unsimulated/wall/planetary/sif,/area/surface/outside/ocean) +"aM" = (/turf/simulated/floor/outdoors/rocks/sif/planetuse,/area/surface/outside/wilderness/normal) +"aN" = (/turf/simulated/floor/water/deep,/area/surface/outside/ocean) +"aO" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/wilderness/normal) +"aP" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/rocks/sif/planetuse,/area/surface/outside/wilderness/normal) +"aQ" = (/obj/effect/zone_divider,/turf/simulated/floor/water,/area/surface/outside/ocean) +"aR" = (/obj/effect/zone_divider,/turf/simulated/floor/water/deep,/area/surface/outside/ocean) +"aS" = (/turf/simulated/floor/wood{outdoors = 1},/area/surface/outside/path/wilderness) +"aT" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/shuttle/shuttle2/mining) +"aU" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/shuttle/shuttle1/mining) +"aV" = (/turf/simulated/floor/outdoors/grass/sif/planetuse{tree_chance = 0},/area/surface/outside/wilderness/normal) +"aW" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/path/wilderness) +"aX" = (/turf/simulated/floor/outdoors/grass/sif/planetuse{tree_chance = 0},/area/shuttle/shuttle2/mining) +"aY" = (/turf/simulated/floor/outdoors/grass/sif/planetuse{tree_chance = 0},/area/shuttle/shuttle1/mining) +"aZ" = (/obj/structure/grille,/obj/structure/window/reinforced/full,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"ba" = (/turf/simulated/wall/log_sif,/area/surface/outpost/shelter) +"bb" = (/obj/effect/zone_divider,/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/path/wilderness) +"bc" = (/obj/structure/simple_door/sifwood,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bd" = (/obj/structure/cable{icon_state = "0-2"; d2 = 2},/obj/machinery/power/port_gen/pacman,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"be" = (/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bf" = (/obj/machinery/recharger/wallcharger{pixel_x = 4; pixel_y = 26},/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bg" = (/obj/structure/table/steel,/obj/machinery/power/apc{dir = 8; locked = 0; name = "west bump"; operating = 0; pixel_x = -24},/obj/structure/cable,/obj/item/stack/material/phoron,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bh" = (/obj/structure/bed/chair{dir = 8},/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bi" = (/obj/structure/closet,/obj/random/maintenance/clean,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bj" = (/obj/structure/table/steel,/obj/machinery/cell_charger,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bk" = (/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/surface/outside/wilderness/mountains) +"bl" = (/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) +"bm" = (/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outside/path/wilderness) +"bn" = (/obj/item/weapon/banner/nt,/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outside/path/wilderness) +"bo" = (/turf/simulated/shuttle/wall/voidcraft/hard_corner,/area/surface/outpost/wall/checkpoint) +"bp" = (/obj/machinery/door/airlock/voidcraft{name = "Wilderness Containment"},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) +"bq" = (/turf/simulated/shuttle/wall/voidcraft,/area/surface/outpost/wall/checkpoint) +"br" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) +"bs" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) +"bt" = (/obj/item/weapon/banner/virgov,/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outside/path/wilderness) +"bu" = (/obj/effect/map_effect/portal/master/side_b/wilderness_to_caves{icon_state = "portal_side_b"; dir = 1},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) +"bv" = (/obj/structure/closet/crate,/obj/random/powercell,/obj/item/weapon/tool/screwdriver,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bw" = (/obj/random/junk,/obj/machinery/embedded_controller/radio/simple_docking_controller{frequency = 1380; id_tag = "mining_dock_1"; name = "shuttle bay controller"; pixel_x = 0; pixel_y = -26; tag_door = "mining_dock_1_door"},/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bx" = (/obj/item/weapon/banner/virgov,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"by" = (/obj/machinery/space_heater,/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bz" = (/obj/machinery/space_heater,/obj/machinery/embedded_controller/radio/simple_docking_controller{frequency = 1380; id_tag = "mining_dock_2"; name = "shuttle bay controller"; pixel_x = 0; pixel_y = -26; tag_door = "mining_dock_2_door"},/turf/simulated/floor/plating/external,/area/surface/outpost/shelter) +"bA" = (/obj/effect/shuttle_landmark{docking_controller = "mining_dock_2"; landmark_tag = "shuttle2_mining"; name = "Wilderness Landing Site"},/turf/simulated/floor/outdoors/grass/sif/planetuse{tree_chance = 0},/area/shuttle/shuttle2/mining) +"bB" = (/obj/effect/shuttle_landmark{docking_controller = "mining_dock_1"; landmark_tag = "shuttle1_mining"; name = "Wilderness Landing Site"},/turf/simulated/floor/outdoors/dirt/sif/planetuse,/area/shuttle/shuttle1/mining) +"bC" = (/obj/effect/map_effect/portal/line/side_b{icon_state = "portal_line_side_b"; dir = 1},/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) +"bD" = (/obj/effect/map_effect/portal/line/side_b{icon_state = "portal_line_side_b"; dir = 1},/turf/simulated/floor/water,/area/surface/outside/ocean) +"bE" = (/obj/effect/map_effect/portal/master/side_b/wilderness_to_caves/river{icon_state = "portal_side_b"; dir = 1},/turf/simulated/floor/water,/area/surface/outside/ocean) +"bF" = (/obj/effect/map_effect/perma_light/concentrated/incandescent,/turf/simulated/shuttle/floor/voidcraft/external,/area/surface/outpost/wall/checkpoint) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaababaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaa +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeaeaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaa +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacaeafaeaeaeafaeaeacacacacacacacacacacacacacacacacafaeaeaeafaeaeacacacacaeacacacacacacacacacaeaeaeaeaeaeaeaeaeacacacacaeaeafaeaeaeafaeaeacacacacacacacacacacacaeaeafafafafafaeaeacacacacacaeaeaeaeaeaeaeaeaeacacacacaeaeaeaeaeagaeacacacacacacacaeaeaeaeacacacacacacaeaeaeaeaeaeaeaeacacacacacacacacacacaeaeaeaeaeaeaeaeaeacacacacacacacacacacacacacacacaa +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeafafafafafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacaa +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacadacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacaa +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacaa +aaacacacacacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacaa +aaacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa +aaacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa +aaacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa +aaacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahaeaeaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa +aaacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaiaiaeaeaeaeaeaeaeaeahahahahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeaeaeaeaeahahahaeahahahahahaiaiaeaiaiaiaiaiaeaeaeaeaeaeaeaeaeaeaeaeaeaiaiaiaiaeaeaeaeaeahahahahahahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeaeaeaeaeaeaeahahahahahahahahahahahahahahahaiaiaiaiaeaeaeaeaeaeaeaeaeaeaeaiaiaiaiaiaiaeaeaeahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahahaeaeaeahahahahahaeahahahaeaeaeaeahahahahaeaeaeaiaiaeaeaeaeaeaeaeaeaeaeaeaiaiaiaiaiaiahahahahaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaiaiahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahaeaeaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaadadadagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagadadadadaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeajajaeaeacacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeajacacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajaeajaeaeaeajajajacacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeaeaeaeajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeajajaeaeajajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeajaeaeaeajajajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajaeaeajajajajajajajajajajajajajacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeajajajajajajajajajajajajajajacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajaeaeaeajajajajajajajajajajajajajajajajajajacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajaeaeajajajajajajajajajajajajajajajajajajajacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajaeaeaeaeajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaiaiaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeajaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaiaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajajajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeaeaeaeaeaeagaeaeaiaiaeaeaeaeaeaeaeajaeaeaeaeajaeaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeaeajaeaeaeaeaeaeaeaeagaeaeaiaiaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeajajajaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaiaiaeaeaeajajaeaeaeaeaeaeaeaeaeaeaeajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeajaeaeaeaeaeaeaeajaeaeajajaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeaeaeagaeaeaeaiaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeajaeaeaeajaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeajajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeajaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajagaeaeaeaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajakaeaeaeaeaeaeajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeakaeaeaeaeajajajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeagaeaeaeaeaeajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeagaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeagaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeagaeajaeaeaeajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagajajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajagaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajagajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa +aaacacahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa +aaacacacahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa +aaacacahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa +alamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa +alamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa +alanananananananamamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +alanananananananananananananananamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +alamamamamamamamananananananananananananananananamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +alamamamamamamamamamamamamamamamamananananananananananananamamamamamamamaeaeamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaoaoaoaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacapamamamamamamamamamamamamamamamamamamananananananananananananamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaoaqararasagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacacapatatatatatatatatatamamamamamamamamamamamamamamamamamamanananananananamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeauararavawamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajakaiajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacacapapatatatatatatatatatatatatatatatamamamamamamamamamamamamamananananananananananananananananamamamamamamamamamamauaraxamawamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa +aaacacacapapatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamananananananananananananananananananananayaSaSazaAananananananananananamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacapapatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamanananananananananaBaSazaAanananananananananananamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajakaiajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacapapatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamamamauararavaAanamamamamamamamanananananananamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacapatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamauararavawamamamamamamamamamamananananananananananananamamamamamamamamamaeaeamamamaeaeaeaeamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamatasararaCaDamamamamamamamamamamamamananananananananananananananananamamamamamamamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajakajaoaoajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataoatataDatatatatatatatamamamamamamamamananananananananananananananananamamanananamamamamanananamamamamamamamamamamamamaeaeaeaeaeamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajajajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataoaoataDatatatatatatatatatatamamamamamamamamamamamamamamamamamanananamamamamanananamamamanananananananananamamamamamamamamamamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataoataDatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamamamamamamamamamamamamamanananananananamamamamamanananananananananamamamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajakajaoaoajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataoataDatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamatatamamamamamamamamamamamamamamamamamamamamamamanananananananananananananananananamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajakajaoaoajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamatatatatatatamamamamamamamamamamanananananananananananananananamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajamamawasararasajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamanananamanananamamananamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajamamamamamawauararavamamamamajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamamamananananamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeajajaeajajajajajajajajajajajajamamamamamamanananaAaEararavananamamamamamajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamananananananamamamamamamamamamaeaeaeaeaeaeaeajajaeajajajajajajajajajajamamamamamamamamananananaAaEararaFananananamamamamamamajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajaeajajajajajajajajajacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamanananananamamamamamamamamamaeaeaeaeaeaeaeajajajajajajajamamamamamamamamamananananananaAaEararaFanananananananamamamamamamamamamamajajajajajajajajajajajajajajajajajajajajajajajaeaeaeajajajajajaeaeaeacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamanananananamamamamamamamamamamamamamajajajamamamamamamamamamamamamananananamamanaAaEararaFananananananananananamamamamamamamamamajajajajajajajajajajajajajajajajajajajajaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamananananamamamamamamamamamamamamamamamamamamamamamamamananananananamamamamawauararavamamamamamamanananananamananananamamamamamajajajajajajajajajajajajajajajajajajaeajaeaeaeaeaeaeajajaeacacacacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamanananananamamamamamamamamamamamamamamananananananananamamamamamamamawauararavamamamamamamamamamamanananananananananamamamamajajajajajajajajajajajajajajajajaeaeaeaeaeaeaeaeaeaeaeacacacacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamanananananamamamamananananananananananananamamamamamamamamamaGaHaCararasaGaGaGaGaGaGamamamamamamamamananananananamamamamamamamamamajajajajajajajajajajajaeaeaeaeaeaeaeaeaeaeacacacacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamanananamamamanananananananamamamamamamamamamamamamaGaGaGaGaGaHaGaoaoaGaGaGaGaGaGaGaGaGamamamamamamamamamamanananananananamamamamamamajajajajajaeajajaeaeaeajajaeaeaeaeajaeacacacacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamamamamamamamaGaGaGaGaGaGaGaGaGaHaGaoaoaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamamananananananananamamamamamamajajajajaeaeaeaeaeajaeaeaeaeaeacacacacacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaoaoaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamanananananananamamamamamamaeaeaeaeajaeaeaeaeaeaeaeaeacacacacacacacaa +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaoaoaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamanananananananamamamamaeaeaeaeaeaeaeaeaeaeaeacacacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaoaoaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamamanananananamamamamaeaeaeaeajaeaeaeaeajacacacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamananananamamamaeaeaeaeajajaeaeaeajacacacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamananananamamamajaeaeaeaeaeaeaeahacacacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaIaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamanananamamamajaeaeaeahaeahahahacacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamananamamamaeahahahahahahahacacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamananamamamahaJaJaJahahahacacacacacacaa +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaIaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamananamamamaJaJaJahahacacacacaKaKaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamananamamamaJaJaJahacacacaKaKaKaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamamamamaJaJaJacaKaKaKaKaKaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapamamamamanamamamaJaJaKaKaKaKaKaKaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaIaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMamamanananamamamaKaKaKaKaKaKaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMamamananamamaKaKaKaKaKaKaKaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMamamananaKaKaKaKaKaKaKaKaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMamamaKaKaKaNaNaKaKaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMamaKaKaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaKaKaKaKaKaKaKaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGaGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaL +aaadadadaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaHaHaHaDaDaHaHaHaHaHaDaDaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaOaOaOaPaPaPaPaQaQaQaQaQaQaQaQaRaRaRaRaRaRaRaRaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaL +aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMaMaKaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatataGaGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGaGatatatataGaGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVapapaVaVapapaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVapapaVapaVaVaVaVapaVaVaVaVaVaVaVapaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGataGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVapapapaVaVaVaVaVaVaVaVaVaVaVaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVapapaXaTaVaVaVaVaVaXaXaVaVaVaVaVaVaVaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVapaXaXaXaVaVaVaXaTaXaVaVaVaVaVaUaUaUaUaUaVaVaVapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVapaVaVaTaTaXaXaXaXaTaXaXaVaVapaVaYaYaUaUaUaYaYaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVapapaVaVaTaTaXaXaXaXaTaXaTaVaVaVaVaYaYaYaUaYaYaUaGaGaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatataGatatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaTbAaXaTaTaTaXaXaTaVaVaVaVaYaUaYaYaUaUaUaGaGaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatataGaGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaXaTaTaTaTaTaTaTaXaVaVaVaVaUaUaUaYaYaYaUaVaVapapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaXaXaTaTaTaTaXaXaXapaVaVaVaUaUaUaUaUaYaYaVaVaVapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatatatatatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaVaTaXaXaXaXaXaTaVaVaVaVaVaYaUaUaUaUaUaYaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaVaTaXaXaXaTaTaTaVaVaVaVaYaYaYaYaUaUaYaYaYaVaVapapaVapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatataGaGatatatataGaGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaVaVapaVaVaXaXaTaXaXaTaTaVapapaVaUaUaYaYaYaYaYaUaUaVaVaVaVapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaTaTaTaTaTaXaXaVaVapaVaUaUaUaYaYaYaYbBaUaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaTaXaXaXaTaTaXaVaVaVaVaUaYaYaYaUaUaYaYaUaVaVapaVaVapaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaXaXaTaTaTaTaTaVaVaVaVaYaYaUaUaUaUaUaYaYaVaVaVapaVaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaVaTaTaTaTaTaVaVaVaVaVaYaUaUaVaVaVaUaUaUaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGataGaGataGaGaGataGaGaGaGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaWaWaWaVaVaVaVaVaVaVaVaYaUaVaWaVaVaVaUaUaVaVaVaVapapaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGataGaGaGaGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaWaVaVaVaVaVaVaVaVaVaVaVaVaVaVaWaWaVaVaVaVaVaVaVaVaVaVaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaVaVaVaVaVaVaVaVaVaVaVaVaVaVaWaWaWaVaVaVaVaVaVapapapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapapaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGaGaGaGaGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaWaWaVaWaVaWaWaWaWaWaWaWaWaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaWaWaWapaMaMaWaWarararaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaGaWaWaWaWaWaWarararaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaGaGaGaGaGaWaWaWaWaWaWaWaWaWaGaGaGaWaWaWaWaGaGaGaGaGaGaGaGaGaGbaaZbabcbaaZbaaGaWaWaWaGaWaWaWaWaWaWaWaGaWaWaWaWaWaWaWaGaGaWaWaWaWaGaGaGaHaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbabdbfbebebebaaGaGaGaGaGaGaGaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWbbaWaGaGaWaWaWaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL +aaacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbabgbhbebebibaaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaKaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaKaKaKaKaKaKaL +aaacacacacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbabjbebebebvbaaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaKaKaKaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaKaKaKaKaKaKaKaL +aaacacacacacacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWbmbmbmaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbabwbybxbebzbaaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaL +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGataGaGaGaGaGaGaGacacacacacacacbkbnblblblbtbkacacacaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbababababababaaGaGaGacacacacacacacacacacaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGacacacacacacacacaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaL +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacatatatatatatatatatatatatatatatacacacacadacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatacacacacacacacacacacacacacacacacacacbobpbqbpboacacacacacacacacacacacacacacacaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaGaGaGadacacacacacacacacaGaGaGaGaGaGaGaGaGaGaGaGaGaGacacacacacacacacacacacacacacacacaKaKaKacacacacaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaL +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacatatatatatatatatatatatatatatatatatacacacacacacacacacacacacacacacacacacacacacacacacbqbrblbsbqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaKaKaKaKaKaKaKaKaKaKaKacacaKaL +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacbqblblblbqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaKaKaKaKaKaKaKacacacacacacaa +aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacbqbubCbCbqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacbEbDbDacacacacacacacacaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqbFbFbFbqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaKaKaKacaaaaaaaaaaaaaaaa +"} -(1,1,1) = {" -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababaaaaaaaaaaaaababaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaa -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeaeaeacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaa -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacaeafaeaeaeafaeaeacacacacacacacacacacacacacacacacafaeaeaeafaeaeacacacacaeacacacacacacacacacaeaeaeaeaeaeaeaeaeacacacacaeaeafaeaeaeafaeaeacacacacacacacacacacacaeaeafafafafafaeaeacacacacacaeaeaeaeaeaeaeaeaeacacacacaeaeaeaeaeagaeacacacacacacacaeaeaeaeacacacacacacaeaeaeaeaeaeaeaeacacacacacacacacacacaeaeaeaeaeaeaeaeaeacacacacacacacacacacacacacacacaa -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeafafafafafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacaa -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacadacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacaa -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacaa -aaacacacacacacacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacacaa -aaacacacacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa -aaacacacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa -aaacacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa -aaacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahaeaeaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa -aaacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaiaiaeaeaeaeaeaeaeaeahahahahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeaeaeaeaeahahahaeahahahahahaiaiaeaiaiaiaiaiaeaeaeaeaeaeaeaeaeaeaeaeaeaiaiaiaiaeaeaeaeaeahahahahahahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahaeaeaeaeaeaeaeaeahahahahahahahahahahahahahahahaiaiaiaiaeaeaeaeaeaeaeaeaeaeaeaiaiaiaiaiaiaeaeaeahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahahaeaeaeahahahahahaeahahahaeaeaeaeahahahahaeaeaeaiaiaeaeaeaeaeaeaeaeaeaeaeaiaiaiaiaiaiahahahahaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahahahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaiaiahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahaeaeaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaadadadagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagagadadadadaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeacacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeajajaeaeacacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeajacacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajaeajaeaeaeajajajacacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeaeaeaeajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeajajaeaeajajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeajaeaeaeajajajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajaeaeajajajajajajajajajajajajajacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeajajajajajajajajajajajajajajacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajaeaeaeajajajajajajajajajajajajajajajajajajacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajaeaeajajajajajajajajajajajajajajajajajajajacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajaeaeaeaeajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaiaiaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeajaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaiaiaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajajajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeaeaeaeaeaeagaeaeaiaiaeaeaeaeaeaeaeajaeaeaeaeajaeaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeaeajaeaeaeaeaeaeaeaeagaeaeaiaiaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeajajajaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaiaiaeaeaeajajaeaeaeaeaeaeaeaeaeaeaeajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeajaeaeaeaeaeaeaeajaeaeajajaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeaeaeaeaeagaeaeaeaiaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeajaeaeaeajaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeajajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeajaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajagaeaeaeaeaeaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajakaeaeaeaeaeaeajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeaeaeaeakaeaeaeaeajajajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeaeagaeaeaeaeaeajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeaeagaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeagaeaeajajaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeagaeajaeaeaeajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagajajaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajagaeajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajagajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa -aaacacahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa -aaacacacahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa -aaacacahahahaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa -alamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa -alamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacaa -alanananananananamamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -alanananananananananananananananamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaiaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -alamamamamamamamananananananananananananananananamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -alamamamamamamamamamamamamamamamamananananananananananananamamamamamamamaeaeamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaoaoaoaeaeagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacapamamamamamamamamamamamamamamamamamamananananananananananananamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaoaqararasagaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacacapatatatatatatatatatamamamamamamamamamamamamamamamamamamanananananananamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeauararavawamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajakaiajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacacapapatatatatatatatatatatatatatatatamamamamamamamamamamamamamananananananananananananananananamamamamamamamamamamauaraxamawamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacaa -aaacacacapapatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamananananananananananananananananananananayaSaSazaAananananananananananamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacapapatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamanananananananananaBaSazaAanananananananananananamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajakaiajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacapapatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamamamauararavaAanamamamamamamamanananananananamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajaeajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacapatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamauararavawamamamamamamamamamamananananananananananananamamamamamamamamamaeaeamamamaeaeaeaeamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamatasararaCaDamamamamamamamamamamamamananananananananananananananananamamamamamamamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajakajaoaoajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataoatataDatatatatatatatamamamamamamamamananananananananananananananananamamanananamamamamanananamamamamamamamamamamamamaeaeaeaeaeamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajaeajajajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataoaoataDatatatatatatatatatatamamamamamamamamamamamamamamamamamanananamamamamanananamamamanananananananananamamamamamamamamamamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajakajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataoataDatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamamamamamamamamamamamamamanananananananamamamamamanananananananananamamamamamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajakajaoaoajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataoataDatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamatatamamamamamamamamamamamamamamamamamamamamamamanananananananananananananananananamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajajajakajaoaoajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamatatatatatatamamamamamamamamamamanananananananananananananananamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajajajajamamawasararasajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamanananamanananamamananamamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeaeaeaeaeaeajajajajajajajajajajajajajajajajamamamamamawauararavamamamamajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamamamananananamamamamamamamamamamamamaeaeaeaeaeaeaeaeaeajajaeajajajajajajajajajajajajamamamamamamanananaAaEararavananamamamamamajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamananananananamamamamamamamamamaeaeaeaeaeaeaeajajaeajajajajajajajajajajamamamamamamamamananananaAaEararaFananananamamamamamamajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajajaeajajajajajajajajajacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamanananananamamamamamamamamamaeaeaeaeaeaeaeajajajajajajajamamamamamamamamamananananananaAaEararaFanananananananamamamamamamamamamamajajajajajajajajajajajajajajajajajajajajajajajaeaeaeajajajajajaeaeaeacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamanananananamamamamamamamamamamamamamajajajamamamamamamamamamamamamananananamamanaAaEararaFananananananananananamamamamamamamamamajajajajajajajajajajajajajajajajajajajajaeaeaeaeaeaeaeaeaeaeaeaeacacacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamananananamamamamamamamamamamamamamamamamamamamamamamamananananananamamamamawauararavamamamamamamanananananamananananamamamamamajajajajajajajajajajajajajajajajajajaeajaeaeaeaeaeaeajajaeacacacacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamanananananamamamamamamamamamamamamamamananananananananamamamamamamamawauararavamamamamamamamamamamanananananananananamamamamajajajajajajajajajajajajajajajajaeaeaeaeaeaeaeaeaeaeaeacacacacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamanananananamamamamananananananananananananamamamamamamamamamaGaHaCararasaGaGaGaGaGaGamamamamamamamamananananananamamamamamamamamamajajajajajajajajajajajaeaeaeaeaeaeaeaeaeaeacacacacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamanananamamamanananananananamamamamamamamamamamamamaGaGaGaGaGaHaGaoaoaGaGaGaGaGaGaGaGaGamamamamamamamamamamanananananananamamamamamamajajajajajaeajajaeaeaeajajaeaeaeaeajaeacacacacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamamamamamamamamamamaGaGaGaGaGaGaGaGaGaHaGaoaoaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamamananananananananamamamamamamajajajajaeaeaeaeaeajaeaeaeaeaeacacacacacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamamamamamamamamamamaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaoaoaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamanananananananamamamamamamaeaeaeaeajaeaeaeaeaeaeaeaeacacacacacacacaa -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatamamamamamamamaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaoaoaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamanananananananamamamamaeaeaeaeaeaeaeaeaeaeaeacacacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaoaoaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamamanananananamamamamaeaeaeaeajaeaeaeaeajacacacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamananananamamamaeaeaeaeajajaeaeaeajacacacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamananananamamamajaeaeaeaeaeaeaeahacacacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaIaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamanananamamamajaeaeaeahaeahahahacacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamananamamamaeahahahahahahahacacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamananamamamahaJaJaJahahahacacacacacacaa -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaIaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamananamamamaJaJaJahahacacacacaKaKaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamananamamamaJaJaJahacacacaKaKaKaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGamamamamamamamamamaJaJaJacaKaKaKaKaKaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapamamamamanamamamaJaJaKaKaKaKaKaKaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaIaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMamamanananamamamaKaKaKaKaKaKaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMamamananamamaKaKaKaKaKaKaKaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMamamananaKaKaKaKaKaKaKaKaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMamamaKaKaKaNaNaKaKaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMamaKaKaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaKaKaKaKaKaKaKaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGaGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaL -aaadadadaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaDaHaHaHaDaDaHaHaHaHaHaDaDaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaHaOaOaOaPaPaPaPaQaQaQaQaQaQaQaQaRaRaRaRaRaRaRaRaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaL -aaacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMaMaKaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaKaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatataGaGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGaGatatatataGaGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVapapaVaVapapaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVapapaVapaVaVaVaVapaVaVaVaVaVaVaVapaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGataGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVapapapaVaVaVaVaVaVaVaVaVaVaVaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVapapaXaTaVaVaVaVaVaXaXaVaVaVaVaVaVaVaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVapaXaXaXaVaVaVaXaTaXaVaVaVaVaVaUaUaUaUaUaVaVaVapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVapaVaVaTaTaXaXaXaXaTaXaXaVaVapaVaYaYaUaUaUaYaYaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVapapaVaVaTaTaXaXaXaXaTaXaTaVaVaVaVaYaYaYaUaYaYaUaGaGaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatataGatatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaTbAaXaTaTaTaXaXaTaVaVaVaVaYaUaYaYaUaUaUaGaGaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatataGaGaGatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaXaTaTaTaTaTaTaTaXaVaVaVaVaUaUaUaYaYaYaUaVaVapapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaXaXaTaTaTaTaXaXaXapaVaVaVaUaUaUaUaUaYaYaVaVaVapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatatatatatatatatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaVaTaXaXaXaXaXaTaVaVaVaVaVaYaUaUaUaUaUaYaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaVaTaXaXaXaTaTaTaVaVaVaVaYaYaYaYaUaUaYaYaYaVaVapapaVapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatataGaGatatatataGaGaGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaVaVapaVaVaXaXaTaXaXaTaTaVapapaVaUaUaYaYaYaYaYaUaUaVaVaVaVapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaTaTaTaTaTaXaXaVaVapaVaUaUaUaYaYaYaYbBaUaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaTaXaXaXaTaTaXaVaVaVaVaUaYaYaYaUaUaYaYaUaVaVapaVaVapaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaXaXaTaTaTaTaTaVaVaVaVaYaYaUaUaUaUaUaYaYaVaVaVapaVaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaVaTaTaTaTaTaVaVaVaVaVaYaUaUaVaVaVaUaUaUaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGataGaGataGaGaGataGaGaGaGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaWaWaWaVaVaVaVaVaVaVaVaYaUaVaWaVaVaVaUaUaVaVaVaVapapaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatatataGataGaGaGaGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaVaVaVaVaVaWaVaVaVaVaVaVaVaVaVaVaVaVaVaVaWaWaVaVaVaVaVaVaVaVaVaVaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaVaVaVaVaVaVaVaVaVaVaVaVaVaVaWaWaWaVaVaVaVaVaVapapapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapapapapaMaMaMaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGaGaGaGaGaGaGaGaGaGapaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaWaWaVaWaVaWaWaWaWaWaWaWaWaVaVaVaVaVaVaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaWaWaWapaMaMaWaWarararaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaGaWaWaWaWaWaWarararaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGapapaGaGaGaGaGaWaWaWaWaWaWaWaWaWaGaGaGaWaWaWaWaGaGaGaGaGaGaGaGaGaGbaaZbabcbaaZbaaGaWaWaWaGaWaWaWaWaWaWaWaGaWaWaWaWaWaWaWaGaGaWaWaWaWaGaGaGaHaWaWaWaWaWaWaWaWaWaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbabdbfbebebebaaGaGaGaGaGaGaGaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWbbaWaGaGaWaWaWaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaMaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaL -aaacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGaGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWaWaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbabgbhbebebibaaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaKaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaNaNaNaKaKaKaKaKaKaL -aaacacacacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGapaWaWaWaWaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbabjbebebebvbaaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaKaKaKaKaKaKaKaKaKaKaKaKaKaNaNaNaNaNaNaNaKaKaKaKaKaKaKaL -aaacacacacacacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGatataGatataGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaWbmbmbmaWaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbabwbybxbebzbaaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaMaMaMaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaL -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataDatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatataGaGatataGataGaGaGaGaGaGaGacacacacacacacbkbnblblblbtbkacacacaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGbababababababaaGaGaGacacacacacacacacacacaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaHaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGacacacacacacacacaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaL -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacatatatatatatatatatatatatatatatacacacacadacacacacacacatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatatacacacacacacacacacacacacacacacacacacbobpbqbpboacacacacacacacacacacacacacacacaGaGaGaGaGaGaGaGaGaGaGaGaGaGaGacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaGaGaGadacacacacacacacacaGaGaGaGaGaGaGaGaGaGaGaGaGaGacacacacacacacacacacacacacacacacaKaKaKacacacacaKaKaKaKaKaKaKaKaKaKaKaKaKaKaKaL -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacatatatatatatatatatatatatatatatatatacacacacacacacacacacacacacacacacacacacacacacacacbqbrblbsbqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaKaKaKaKaKaKaKaKaKaKaKacacaKaL -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacbqblblblbqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaKaKaKaKaKaKaKacacacacacacaa -aaacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacbqbubCbCbqacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacadacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacbEbDbDacacacacacacacacaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqbFbFbFbqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaKaKaKacaaaaaaaaaaaaaaaa -"} - diff --git a/maps/southern_cross/southern_cross_defines.dm b/maps/southern_cross/southern_cross_defines.dm index 8d11290989..bc8ea8e383 100644 --- a/maps/southern_cross/southern_cross_defines.dm +++ b/maps/southern_cross/southern_cross_defines.dm @@ -250,8 +250,7 @@ expected_z_levels = list( Z_LEVEL_SURFACE, Z_LEVEL_SURFACE_MINE, - Z_LEVEL_SURFACE_WILD, - Z_LEVEL_TRANSIT + Z_LEVEL_SURFACE_WILD ) /obj/effect/step_trigger/teleporter/bridge/east_to_west/Initialize() @@ -326,4 +325,4 @@ name = "Pilot suit cycler" model_text = "Pilot" req_access = null - req_one_access = list(access_pilot,access_explorer) \ No newline at end of file + req_one_access = list(access_pilot,access_explorer) diff --git a/maps/submaps/surface_submaps/mountains/spatial_anomaly.dmm b/maps/submaps/surface_submaps/mountains/spatial_anomaly.dmm index 3f05b9ef41..0adb4b8937 100644 --- a/maps/submaps/surface_submaps/mountains/spatial_anomaly.dmm +++ b/maps/submaps/surface_submaps/mountains/spatial_anomaly.dmm @@ -1,82 +1,82 @@ -"a" = (/turf/simulated/wall/solidrock,/area/submap/spatial_anomaly) -"b" = (/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"c" = (/obj/effect/map_effect/portal/master/side_a{dir = 4; icon_state = "portal_side_a"; portal_id = "spatial_anomaly_5"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"d" = (/obj/effect/map_effect/portal/master/side_b{dir = 8; icon_state = "portal_side_b"; portal_id = "spatial_anomaly_5"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"e" = (/obj/structure/barricade,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"f" = (/turf/template_noop,/area/template_noop) -"g" = (/obj/effect/map_effect/portal/master/side_b{portal_id = "spatial_anomaly_4"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"h" = (/obj/effect/map_effect/portal/line/side_a{icon_state = "portal_line_side_a"; dir = 4},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"i" = (/obj/effect/map_effect/portal/line/side_b{icon_state = "portal_line_side_b"; dir = 8},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"j" = (/turf/simulated/floor/lava,/area/submap/spatial_anomaly) -"k" = (/obj/item/weapon/disposable_teleporter/slime,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"l" = (/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"m" = (/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"n" = (/obj/effect/map_effect/portal/master/side_a{dir = 4; icon_state = "portal_side_a"; portal_id = "spatial_anomaly_3"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"o" = (/obj/effect/map_effect/portal/master/side_a{dir = 1; icon_state = "portal_side_a"; portal_id = "spatial_anomaly_4"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"p" = (/obj/effect/map_effect/portal/master/side_b{dir = 8; icon_state = "portal_side_b"; portal_id = "spatial_anomaly_3"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"q" = (/obj/effect/map_effect/portal/master/side_b{portal_id = "spatial_anomaly_2"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"r" = (/obj/effect/map_effect/portal/line/side_b,/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"s" = (/obj/machinery/crystal/lava,/turf/simulated/floor/lava,/area/submap/spatial_anomaly) -"t" = (/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"u" = (/obj/effect/map_effect/portal/master/side_a{portal_id = "spatial_anomaly_1"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"v" = (/obj/item/weapon/stool/padded,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"w" = (/obj/structure/table/steel_reinforced,/obj/item/device/xenoarch_multi_tool,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"x" = (/turf/simulated/wall/solidrock,/area/template_noop) -"y" = (/obj/random/technology_scanner,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"z" = (/obj/structure/table/steel_reinforced,/obj/random/unidentified_medicine/scientific,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"A" = (/obj/structure/table/steel_reinforced,/obj/random/tool/power,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"B" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/ore/diamond,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"C" = (/obj/structure/sign/warning/lava,/turf/simulated/wall,/area/submap/spatial_anomaly) -"D" = (/obj/effect/map_effect/portal/line/side_a,/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"E" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe/jackhammer,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"F" = (/obj/effect/map_effect/portal/master/side_a{dir = 1; icon_state = "portal_side_a"; portal_id = "spatial_anomaly_2"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"G" = (/obj/effect/map_effect/portal/line/side_a{icon_state = "portal_line_side_a"; dir = 1},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"H" = (/turf/unsimulated/wall,/area/template_noop) -"I" = (/obj/effect/map_effect/portal/master/side_b{dir = 1; icon_state = "portal_side_b"; portal_id = "spatial_anomaly_1"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"J" = (/obj/effect/map_effect/portal/line/side_b{icon_state = "portal_line_side_b"; dir = 1},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"K" = (/obj/item/weapon/mining_scanner,/obj/structure/table/rack,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"L" = (/obj/item/weapon/storage/belt/archaeology,/obj/effect/decal/remains/human,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"M" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"N" = (/obj/item/weapon/pickaxe/brush,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"O" = (/obj/item/weapon/pickaxe/one_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"P" = (/obj/item/weapon/pickaxe/four_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"Q" = (/obj/effect/decal/remains/human,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) -"R" = (/obj/item/weapon/pickaxe/five_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"S" = (/obj/item/weapon/pickaxe/six_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"T" = (/obj/item/weapon/pickaxe/two_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"U" = (/obj/item/device/measuring_tape,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"X" = (/obj/item/weapon/pickaxe/three_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) -"Y" = (/obj/item/weapon/pickaxe/excavationdrill,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) - -(1,1,1) = {" -ffffffffffffffffffffffffffffff -fffffffffffffxxxxxxfffffffffff -fffffxxxxxxxxaaaaaaxxxxxffffff -ffffxaaaaaaaaaaaaaaaaaaaxfffff -ffffaataatcbbbbjjjsjkbdtaxffff -fffxaagaathbbbbbjjjjbbitaaffff -fffaaabaaaaaabCbbsaaaaaaaaffff -fffaaaObaaaabbNbbaaaaaaaaaxfff -ffxaaabbblbbbybbaabPbbblaaafff -ffaaaaaaaaabbbtmaabbaaabaaafff -ffaaaaaaaaatttttaabaaaabaaafff -ffaalbbbbbaatvtQaalaaaabaaafff -ffaabaaaabaaBwzAaabaaaabaaffff -ffaabaaaabaaaaaaaabatnbbaaHHHf -ffxabaaaaoaaaaaaabbaaaaaaaffHf -ffxabaaaataatttaabbaaaaaaaffHf -ffxabRbptaaaqrraabSaatttaaHHaf -ffxaaaaaaaaabbbaabbaauDDablbaf -fffaaaaaaaaabbbaablaabbbaeeaaf -fffaaaalbbbabbbaabbaabbbblbaaf -ffffaabbaabababbbbbaaUbbbEKaff -ffffaaTbbabXbabbLbYaabbbaaaaff -ffffaabbbabbbabbmttaaFGGaaafff -ffffaaIJJablbabtttMaatttaaffff -fffffatttaaaaaaaaaaaaaaaafffff -fffffaaaaaaaaaaaaaaaaaaaffffff -fffffaaaaffaaaaaaaafffffffffff -ffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffff -"} +"a" = (/turf/simulated/wall/solidrock,/area/submap/spatial_anomaly) +"b" = (/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"c" = (/obj/effect/map_effect/portal/master/side_a{dir = 4; icon_state = "portal_side_a"; portal_id = "spatial_anomaly_5"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"d" = (/obj/effect/map_effect/portal/master/side_b{dir = 8; icon_state = "portal_side_b"; portal_id = "spatial_anomaly_5"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"e" = (/obj/structure/barricade,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"f" = (/turf/template_noop,/area/template_noop) +"g" = (/obj/effect/map_effect/portal/master/side_b{portal_id = "spatial_anomaly_4"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"h" = (/obj/effect/map_effect/portal/line/side_a{icon_state = "portal_line_side_a"; dir = 4},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"i" = (/obj/effect/map_effect/portal/line/side_b{icon_state = "portal_line_side_b"; dir = 8},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"j" = (/turf/simulated/floor/lava,/area/submap/spatial_anomaly) +"k" = (/obj/item/weapon/disposable_teleporter/slime,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"l" = (/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"m" = (/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"n" = (/obj/effect/map_effect/portal/master/side_a{dir = 4; icon_state = "portal_side_a"; portal_id = "spatial_anomaly_3"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"o" = (/obj/effect/map_effect/portal/master/side_a{dir = 1; icon_state = "portal_side_a"; portal_id = "spatial_anomaly_4"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"p" = (/obj/effect/map_effect/portal/master/side_b{dir = 8; icon_state = "portal_side_b"; portal_id = "spatial_anomaly_3"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"q" = (/obj/effect/map_effect/portal/master/side_b{portal_id = "spatial_anomaly_2"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"r" = (/obj/effect/map_effect/portal/line/side_b,/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"s" = (/obj/machinery/crystal/lava,/turf/simulated/floor/lava,/area/submap/spatial_anomaly) +"t" = (/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"u" = (/obj/effect/map_effect/portal/master/side_a{portal_id = "spatial_anomaly_1"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"v" = (/obj/item/weapon/stool/padded,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"w" = (/obj/structure/table/steel_reinforced,/obj/item/device/xenoarch_multi_tool,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"x" = (/turf/simulated/wall/solidrock,/area/template_noop) +"y" = (/obj/random/technology_scanner,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"z" = (/obj/structure/table/steel_reinforced,/obj/random/unidentified_medicine/scientific,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"A" = (/obj/structure/table/steel_reinforced,/obj/random/tool/power,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"B" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/ore/diamond,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"C" = (/obj/structure/sign/warning/lava,/turf/simulated/wall,/area/submap/spatial_anomaly) +"D" = (/obj/effect/map_effect/portal/line/side_a,/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"E" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe/jackhammer,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"F" = (/obj/effect/map_effect/portal/master/side_a{dir = 1; icon_state = "portal_side_a"; portal_id = "spatial_anomaly_2"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"G" = (/obj/effect/map_effect/portal/line/side_a{icon_state = "portal_line_side_a"; dir = 1},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"H" = (/turf/unsimulated/wall,/area/template_noop) +"I" = (/obj/effect/map_effect/portal/master/side_b{dir = 1; icon_state = "portal_side_b"; portal_id = "spatial_anomaly_1"},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"J" = (/obj/effect/map_effect/portal/line/side_b{icon_state = "portal_line_side_b"; dir = 1},/obj/effect/map_effect/perma_light/brighter{light_color = "#ff00ff"},/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"K" = (/obj/item/weapon/mining_scanner,/obj/structure/table/rack,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"L" = (/obj/item/weapon/storage/belt/archaeology,/obj/effect/decal/remains/human,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"M" = (/obj/structure/bookcase/manuals/xenoarchaeology,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"N" = (/obj/item/weapon/pickaxe/brush,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"O" = (/obj/item/weapon/pickaxe/one_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"P" = (/obj/item/weapon/pickaxe/four_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"Q" = (/obj/effect/decal/remains/human,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) +"R" = (/obj/item/weapon/pickaxe/five_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"S" = (/obj/item/weapon/pickaxe/six_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"T" = (/obj/item/weapon/pickaxe/two_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"U" = (/obj/item/device/measuring_tape,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"X" = (/obj/item/weapon/pickaxe/three_pick,/turf/simulated/floor/outdoors/rocks/caves,/area/submap/spatial_anomaly) +"Y" = (/obj/item/weapon/pickaxe/excavationdrill,/turf/simulated/floor/plating/external,/area/submap/spatial_anomaly) + +(1,1,1) = {" +ffffffffffffffffffffffffffffff +fffffffffffffxxxxxxfffffffffff +fffffxxxxxxxxaaaaaaxxxxxffffff +ffffxaaaaaaaaaaaaaaaaaaaxfffff +ffffaataatcbbbbjjjsjkbdtaxffff +fffxaagaathbbbbbjjjjbbitaaffff +fffaaabaaaaaabCbbsaaaaaaaaffff +fffaaaObaaaabbNbbaaaaaaaaaxfff +ffxaaabbblbbbybbaabPbbblaaafff +ffaaaaaaaaabbbtmaabbaaabaaafff +ffaaaaaaaaatttttaabaaaabaaafff +ffaalbbbbbaatvtQaalaaaabaaafff +ffaabaaaabaaBwzAaabaaaabaaffff +ffaabaaaabaaaaaaaabatnbbaaHHHf +ffxabaaaaoaaaaaaabbaaaaaaaffHf +ffxabaaaataatttaabbaaaaaaaffHf +ffxabRbptaaaqrraabSaatttaaHHaf +ffxaaaaaaaaabbbaabbaauDDablbaf +fffaaaaaaaaabbbaablaabbbaeeaaf +fffaaaalbbbabbbaabbaabbbblbaaf +ffffaabbaabababbbbbaaUbbbEKaff +ffffaaTbbabXbabbLbYaabbbaaaaff +ffffaabbbabbbabbmttaaFGGaaafff +ffffaaIJJablbabtttMaatttaaffff +fffffatttaaaaaaaaaaaaaaaafffff +fffffaaaaaaaaaaaaaaaaaaaffffff +fffffaaaaffaaaaaaaafffffffffff +ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffff +"} diff --git a/maps/tether/tether_phoronlock.dm b/maps/tether/tether_phoronlock.dm index 9118284285..3afc89ebce 100644 --- a/maps/tether/tether_phoronlock.dm +++ b/maps/tether/tether_phoronlock.dm @@ -126,49 +126,18 @@ obj/machinery/airlock_sensor/phoron/airlock_exterior //Advanced airlock controller for when you want a more versatile airlock controller - useful for turning simple access control rooms into airlocks /obj/machinery/embedded_controller/radio/airlock/phoron name = "Phoron Lock Controller" + valid_actions = list("cycle_ext", "cycle_int", "force_ext", "force_int", "abort", "secure") -/obj/machinery/embedded_controller/radio/airlock/phoron/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data = list( +/obj/machinery/embedded_controller/radio/airlock/phoron/tgui_data(mob/user) + . = list( "chamber_pressure" = program.memory["chamber_sensor_pressure"], "chamber_phoron" = program.memory["chamber_sensor_phoron"], "exterior_status" = program.memory["exterior_status"], "interior_status" = program.memory["interior_status"], - "processing" = program.memory["processing"] + "processing" = program.memory["processing"], + "internalTemplateName" = "AirlockConsolePhoron", ) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "phoron_airlock_console.tmpl", name, 470, 290) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/embedded_controller/radio/airlock/phoron/Topic(href, href_list) - if((. = ..())) - return - - var/clean = 0 - switch(href_list["command"]) //anti-HTML-hacking checks - if("cycle_ext") - clean = 1 - if("cycle_int") - clean = 1 - if("force_ext") - clean = 1 - if("force_int") - clean = 1 - if("abort") - clean = 1 - if("secure") - clean = 1 - - if(clean) - program.receive_user_command(href_list["command"]) - - return 1 - // // PHORON LOCK CONTROLLER PROGRAM // diff --git a/nano/images/tether_nanomap_z1.png b/nano/images/tether_nanomap_z1.png index bd575097c3..c463bd04b7 100644 Binary files a/nano/images/tether_nanomap_z1.png and b/nano/images/tether_nanomap_z1.png differ diff --git a/nano/templates/advanced_airlock_console.tmpl b/nano/templates/advanced_airlock_console.tmpl deleted file mode 100644 index e60cf7c932..0000000000 --- a/nano/templates/advanced_airlock_console.tmpl +++ /dev/null @@ -1,60 +0,0 @@ -
-
-
- External Pressure: -
-
- {{:helper.displayBar(data.external_pressure, 0, 200, (data.external_pressure < 80 || data.external_pressure > 120) ? 'bad' : (data.external_pressure < 95 || data.external_pressure > 110) ? 'average' : 'good')}} -
- {{:data.external_pressure}} kPa -
-
-
-
-
- Chamber Pressure: -
-
- {{:helper.displayBar(data.chamber_pressure, 0, 200, (data.chamber_pressure < 80 || data.chamber_pressure > 120) ? 'bad' : (data.chamber_pressure < 95 || data.chamber_pressure > 110) ? 'average' : 'good')}} -
- {{:data.chamber_pressure}} kPa -
-
-
-
-
- Internal Pressure: -
-
- {{:helper.displayBar(data.internal_pressure, 0, 200, (data.internal_pressure < 80 || data.internal_pressure > 120) ? 'bad' : (data.internal_pressure < 95 || data.internal_pressure > 110) ? 'average' : 'good')}} -
- {{:data.internal_pressure}} kPa -
-
-
-
-
-
-
- {{:helper.link('Cycle to Exterior', 'arrowthickstop-1-w', {'command' : 'cycle_ext'}, data.processing ? 'disabled' : null)}} - {{:helper.link('Cycle to Interior', 'arrowthickstop-1-e', {'command' : 'cycle_int'}, data.processing ? 'disabled' : null)}} -
-
- {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, data.processing ? 'yellowButton' : null)}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, data.processing ? 'yellowButton' : null)}} -
-
-
-
-
- {{:helper.link('Purge', 'refresh', {'command' : 'purge'}, data.processing ? 'disabled' : null, data.purge ? 'linkOn' : null)}} -
-
- {{:helper.link('Secure', data.secure ? 'locked' : 'unlocked', {'command' : 'secure'}, data.processing ? 'disabled' : null, data.secure ? 'linkOn' : null)}} -
-
-
-
- {{:helper.link('Abort', 'cancel', {'command' : 'abort'}, data.processing ? null : 'disabled', data.processing ? 'redButton' : null)}} -
-
\ No newline at end of file diff --git a/nano/templates/aicard.tmpl b/nano/templates/aicard.tmpl deleted file mode 100644 index 40a192a165..0000000000 --- a/nano/templates/aicard.tmpl +++ /dev/null @@ -1,103 +0,0 @@ - - - - -{{if data.has_ai}} -
-
- Hardware Integrity: -
-
- {{:data.hardware_integrity}}% -
-
- Backup Capacitor: -
-
- {{:data.backup_capacitor}}% -
-
- - {{if data.has_laws}} - - - -
- Laws: -
- {{for data.laws}} - - {{/for}} -
IndexLaw
{{:value.index}}.{{:value.law}}
- {{else}} - No laws found. - {{/if}} - - {{if data.operational}} - - - - - - - - - - - {{if data.flushing}} - - {{else}} - - - - - {{/if}} -
Radio Subspace Transceiver{{:helper.link("Enabled", null, {'radio' : 0}, data.radio ? 'selected' : null)}}{{:helper.link("Disabled", null, {'radio' : 1}, data.radio ? null : 'redButton' )}}
Wireless Interface{{:helper.link("Enabled", null, {'wireless' : 0}, data.wireless ? 'selected' : null)}}{{:helper.link("Disabled", null, {'wireless' : 1}, data.wireless ? null : 'redButton' )}}
AI shutdown in progress...
AI Power{{:helper.link("Shutdown", 'radiation', {'wipe' : 1}, null, 'redButton')}}
- {{/if}} -{{else}} - Stored AI: No AI detected. -{{/if}} diff --git a/nano/templates/air_alarm.tmpl b/nano/templates/air_alarm.tmpl deleted file mode 100644 index 5914d32646..0000000000 --- a/nano/templates/air_alarm.tmpl +++ /dev/null @@ -1,217 +0,0 @@ - -

Air Status

-{{if data.has_environment}} - {{for data.environment}} - {{:value.name}}: - {{if value.danger_level == 2}} - - {{else value.danger_level == 1}} - - {{else}} - - {{/if}} - {{:helper.fixed(value.value, 1)}} - {{:value.unit}}
- {{/for}} - Local Status: {{if data.total_danger == 2}} - DANGER: Internals Required - {{else data.total_danger == 1}} - Caution - {{else}} - Optimal - {{/if}} -
- Area Status: {{if data.atmos_alarm}}Atmosphere alert in area{{else data.fire_alarm}}Fire alarm in area{{else}}No alerts{{/if}} -{{else}} - Warning: Cannot obtain air sample for analysis. -{{/if}} -
- - - - - - - - - - - - - -
-
-

Remote Control

-
-

Thermostat

-
-
-
-
- {{:helper.link('Off', null, { 'rcon' : 1}, data.remote_connection && !data.remote_access ? (data.rcon == 1 ? 'yellowButton' : 'disabled') : null, data.rcon == 1 ? 'selected' : null)}} - {{:helper.link('Auto', null, { 'rcon' : 2}, data.remote_connection && !data.remote_access ? (data.rcon == 2 ? 'yellowButton' : 'disabled') : null, data.rcon == 2 ? 'selected' : null)}} - {{:helper.link('On', null, { 'rcon' : 3}, data.remote_connection && !data.remote_access ? (data.rcon == 3 ? 'yellowButton' : 'disabled') : null, data.rcon == 3 ? 'selected' : null)}} -
-
-
- {{:helper.link(data.target_temperature, null, { 'temperature' : 1})}} -
-
-{{if (data.locked && !data.remote_connection) || (data.remote_connection && ! data.remote_access)}} - {{if data.remote_connection}} - (Current remote control settings and alarm status restricts access.) - {{else}} - (Swipe ID card to unlock interface.) - {{/if}} -{{else}} - {{if data.screen != 1}} -
{{:helper.link('Main Menu', null, { 'screen' : 1})}}
- {{/if}} - {{if data.screen == 1}} -
- {{if data.atmos_alarm}} - {{:helper.link('Reset - Area Atmospheric Alarm', null, { 'atmos_reset' : 1})}} - {{else}} - {{:helper.link('Activate - Area Atmospheric Alarm', null, { 'atmos_alarm' : 1})}} - {{/if}} -
-
-
- {{:helper.link('Scrubbers Control', null, { 'screen' : 3})}} -
-
- {{:helper.link('Vents Control', null, { 'screen' : 2})}} -
-
- {{:helper.link('Set Environmental Mode', null, { 'screen' : 4})}} -
-
- {{:helper.link('Sensor Settings', null, { 'screen' : 5})}} -
-
- {{if data.mode==3}} - {{:helper.link('PANIC SIPHON ACTIVE - Turn siphoning off', null, { 'mode' : 1}, null, 'redButton')}} - {{else}} - {{:helper.link('ACTIVATE PANIC SIPHON IN AREA', null, { 'mode' : 3}, null, 'yellowButton')}} - {{/if}} - {{else data.screen == 2}} - {{for data.vents}} -
- {{:value.long_name}}
-
-
- Operating: -
-
- {{:helper.link(value.power ? 'On' : 'Off', null, { 'id_tag' : value.id_tag, 'command' : 'power', 'val' : value.power ? 0 : 1}, null, value.power ? null : 'redButton')}} -
-
-
-
- Operation Mode: -
-
- {{:helper.link(value.direction == "siphon" ? 'Siphoning' : 'Pressurizing', null, { 'id_tag' : value.id_tag, 'command' : 'direction', 'val' : value.direction == "siphon" ? 1 : 0}, null, value.direction == "siphon" ? 'redButton' : null)}} -
-
-
-
- Pressure Checks: -
-
- {{:helper.link('External', null, { 'id_tag' : value.id_tag, 'command' : 'checks', 'val' : value.checks^1}, null, value.checks&1 ? 'selected' : null)}} - {{:helper.link('Internal', null, { 'id_tag' : value.id_tag, 'command' : 'checks', 'val' : value.checks^2}, null, value.checks&2 ? 'selected' : null)}} -
-
-
-
- External Pressure Bound: -
-
- {{:helper.link(helper.fixed(value.external,2), null, { 'id_tag' : value.id_tag, 'command' : 'set_external_pressure'})}} - {{:helper.link('Reset', null, { 'id_tag' : value.id_tag, 'command' : 'reset_external_pressure'})}} -
-
-
- {{empty}} - No vents connected. - {{/for}} - {{else data.screen == 3}} - {{for data.scrubbers}} -
- {{:value.long_name}}
-
-
- Operating: -
-
- {{:helper.link(value.power ? 'On' : 'Off', null, { 'id_tag' : value.id_tag, 'command' : 'power', 'val' : value.power ? 0 : 1}, null, value.power ? null : 'redButton')}} -
-
-
-
- Operation Mode: -
-
- {{:helper.link(value.scrubbing ? 'Scrubbing' : 'Siphoning', null, { 'id_tag' : value.id_tag, 'command' : 'scrubbing', 'val' : value.scrubbing ? 0 : 1}, null, value.scrubbing ? null : 'redButton')}} -
-
-
-
- Filters: -
-
- {{for value.filters :filterValue:filterIndex}} - {{:helper.link(filterValue.name, null, { 'id_tag' : value.id_tag, 'command' : filterValue.command, 'val' : filterValue.val ? 0 : 1}, null, filterValue.val ? 'selected' : null)}} - {{/for}} -
-
-
- {{empty}} - No scrubbers connected. - {{/for}} - {{else data.screen == 4}} -

Environmental Modes

- {{for data.modes}} -
- {{:helper.link(value.name, null, { 'mode' : value.mode }, null, value.selected ? (value.danger ? 'redButton' : 'selected') : null)}} -
- {{/for}} - {{else data.screen == 5}} -

Alarm Threshold

- Partial pressure for gases. - - - - - {{for data.thresholds}} - - - {{for value.settings :settingsValue:settingsIndex}} - - {{/for}} - - {{/for}} -
min2min1max1max2
{{:value.name}} - {{:helper.link(settingsValue.selected >= 0 ? helper.fixed(settingsValue.selected, 2) : "Off", null, { 'command' : 'set_threshold', 'env' : settingsValue.env, 'var' : settingsValue.val })}} -
- {{/if}} -{{/if}} - \ No newline at end of file diff --git a/nano/templates/alarm_monitor.tmpl b/nano/templates/alarm_monitor.tmpl deleted file mode 100644 index 2591763fc0..0000000000 --- a/nano/templates/alarm_monitor.tmpl +++ /dev/null @@ -1,38 +0,0 @@ - - -{{for data.categories}} -

{{:value.category}}

- {{for value.alarms :alarmValue:alarmIndex}} - {{if alarmValue.origin_lost}} - {{:alarmValue.name}} Alarm Origin Lost
- {{else}} - {{:alarmValue.name}}
- {{/if}} - {{if alarmValue.has_cameras || alarmValue.lost_sources != ""}} -
- {{if alarmValue.has_cameras}} -
- {{for alarmValue.cameras :cameraValue:cameraIndex}} - {{if cameraValue.deact}} - {{:helper.link(cameraValue.name + " (deactivated)", '', {}, 'inactive')}} - {{else}} - {{:helper.link(cameraValue.name, '', {'switchTo' : cameraValue.camera})}} - {{/if}} - {{/for}} -
- {{/if}} - {{if alarmValue.lost_sources != ""}} -
-

Lost Alarm Sources: {{:alarmValue.lost_sources}}

-
- {{/if}} -
- {{/if}} - {{empty}} - --All Systems Nominal - {{/for}} -{{/for}} diff --git a/nano/templates/algae_farm_vr.tmpl b/nano/templates/algae_farm_vr.tmpl deleted file mode 100644 index be730d9d65..0000000000 --- a/nano/templates/algae_farm_vr.tmpl +++ /dev/null @@ -1,70 +0,0 @@ - -{{if data.errorText }} -
{{:data.errorText}}

-{{/if}} - -
-
- {{if data.usePower==2}} - {{:helper.link('Deactivate Processing', 'power', {'deactivate' : 1})}} - {{else}} - {{:helper.link('Activate Processing', 'power', {'activate' : 1})}} - {{/if}} -
-
-
Flow Rate
-
{{:helper.fixed(data.last_flow_rate)}} L/s
-
-
-
Power Draw
-
{{:helper.formatNumber(data.last_power_draw)}} Watts
-
-
- -

Materials

-
- {{for data.materials }} -
-
{{:value.display.toTitleCase()}}
-
{{:helper.displayBar(value.percent, 0, 100, - (value.percent < 25) ? 'bad' : (value.percent < 50) ? 'average' : 'good', - value.qty + "/" + value.max )}}
-
{{:helper.link("Eject", 'eject', {'ejectMaterial' : value.name })}}
-
- {{/for}} -
- -

Gas Input ({{:data.inputDir}})

-
- {{if data.input}} -
-
Total Pressure
-
{{:data.input.pressure}} kPa
-
-
-
{{:data.input.name}}
-
{{:helper.fixed(data.input.percent)}}% ({{:helper.fixed(data.input.moles)}} moles)
-
- {{else}} -
Not Connected
- {{/if}} -
- -

Gas Output ({{:data.outputDir}})

-
- {{if data.output}} -
-
Total Pressure
-
{{:data.output.pressure}} kPa
-
-
-
{{:data.output.name}}
-
{{:helper.fixed(data.output.percent)}}% ({{:helper.fixed(data.output.moles)}} moles)
-
- {{else}} -
Not Connected
- {{/if}} -
diff --git a/nano/templates/apc.tmpl b/nano/templates/apc.tmpl deleted file mode 100644 index a26abef4a0..0000000000 --- a/nano/templates/apc.tmpl +++ /dev/null @@ -1,229 +0,0 @@ -{{if data.gridCheck}} -
-

SYSTEM FAILURE

- Power surge detected, grid check in effect...
-
-{{else data.failTime}} -
-

SYSTEM FAILURE

- I/O regulators malfunction detected! Waiting for system reboot...
- Automatic reboot in {{:data.failTime}} seconds...
- {{if !data.siliconUser}} - {{if data.locked}} - Swipe an ID card for manual reboot.


- {{else}} - {{:helper.link('Reboot Now', 'refresh', {'reboot' : 1})}}


- {{/if}} - {{else}} - {{:helper.link('Reboot Now', 'refresh', {'reboot' : 1})}}


- {{/if}} -
-{{else}} -
- {{if data.siliconUser}} -
- Interface Lock: -
-
- {{:helper.link('Engaged', 'locked', {'toggleaccess' : 1}, data.locked ? 'selected' : null)}}{{:helper.link('Disengaged', 'unlocked', {'toggleaccess' : 1}, data.malfStatus >= 2 ? 'linkOff' : (data.locked ? null : 'selected'))}} -
-
- {{else}} - {{if data.emagged}} -

Fault in ID authenticator

- Please contact maintenance for service. - {{else data.locked}} - Swipe an ID card to unlock this interface - {{else}} - Swipe an ID card to lock this interface - {{/if}} - {{/if}} -
- -
- -

Power Status

- -
-
- Main Breaker: -
-
- {{if data.locked && !data.siliconUser}} - {{if data.isOperating}} - On - {{else}} - Off - {{/if}} - {{else}} - {{:helper.link('On', 'power', {'breaker' : 1}, data.isOperating ? 'selected' : null)}}{{:helper.link('Off', 'close', {'breaker' : 1}, data.isOperating ? null : 'selected')}} - {{/if}} -
-
- -
-
- External Power: -
-
- {{if data.externalPower == 2}} - Good - {{else data.externalPower == 1}} - Low - {{else}} - None - {{/if}} -
-
- -
-
- Power Cell: -
- {{if data.powerCellStatus == null}} -
- Power cell removed. -
- {{else}} - - {{:helper.displayBar(data.powerCellStatus, 0, 100, (data.powerCellStatus >= 50) ? 'good' : (data.powerCellStatus >= 25) ? 'average' : 'bad')}} -
- {{:helper.round(data.powerCellStatus*10)/10}}% -
- {{/if}} -
- - {{if data.powerCellStatus != null}} -
-
- Charge Mode: -
-
- {{if data.locked && !data.siliconUser}} - {{if data.chargeMode}} - Auto - {{else}} - Off - {{/if}} - {{else}} - {{:helper.link('Auto', 'refresh', {'cmode' : 1}, data.chargeMode ? 'selected' : null)}}{{:helper.link('Off', 'close', {'cmode' : 1}, data.chargeMode ? null : 'selected')}} - {{/if}} -   - {{if data.chargingStatus > 1}} - [Fully Charged] - {{else data.chargingStatus == 1}} - [Charging] - {{else}} - [Not Charging] - {{/if}} -
-
- {{/if}} - - -

Power Channels

- - {{for data.powerChannels}} -
-
- {{:value.title}}: -
-
- {{:value.powerLoad}} W -
-
-    - {{if value.status <= 1}} - Off - {{else value.status >= 2}} - On - {{/if}} - {{if data.locked}} - {{if value.status == 1 || value.status == 3}} -   Auto - {{else}} -   Manual - {{/if}} - {{/if}} -
- {{if !data.locked || data.siliconUser}} -
- {{:helper.link('Auto', 'refresh', value.topicParams.auto, (value.status == 1 || value.status == 3) ? 'selected' : null)}} - {{:helper.link('On', 'power', value.topicParams.on, (value.status == 2) ? 'selected' : null)}} - {{:helper.link('Off', 'close', value.topicParams.off, (value.status == 0) ? 'selected' : null)}} -
- {{/if}} -
- {{/for}} - -
-
- Total Load: -
-
- {{if data.totalCharging}} - {{:data.totalLoad}}W (+ {{:data.totalCharging}}W Charging) - {{else}} - {{:data.totalLoad}}W - {{/if}} -
-
- -
 
- -
-
- Cover Lock: -
-
- {{if data.locked && !data.siliconUser}} - {{if data.coverLocked}} - Engaged - {{else}} - Disengaged - {{/if}} - {{else}} - {{:helper.link('Engaged', 'locked', {'lock' : 1}, data.coverLocked ? 'selected' : null)}}{{:helper.link('Disengaged', 'unlocked', {'lock' : 1}, data.coverLocked ? null : 'selected')}} - {{/if}} -
-
- -
-
- Emergency Lighting: -
-
- {{if data.locked && !data.siliconUser}} - {{:data.emergencyLights ? "Enabled" : "Disabled"}} - {{else}} - {{:helper.link(data.emergencyLights ? 'Enabled' : 'Disabled', data.emergencyLights ? 'power' : 'close', {'emergency_lighting' : 1}, null)}} - {{/if}} -
-
- -
-
- Night Lighting: -
-
- {{:helper.link('Disabled', null, {'nightshift' : 2}, data.nightshiftSetting == 2 ? 'selected' : null)}} - {{:helper.link('Automatic', null, {'nightshift' : 1}, data.nightshiftSetting == 1 ? 'selected' : null)}} - {{:helper.link('Enabled', null, {'nightshift' : 3}, data.nightshiftSetting == 3 ? 'selected' : null)}} -
-
- - {{if data.siliconUser}} -

System Overrides

- -
- {{:helper.link('Overload Lighting Circuit', 'lightbulb', {'overload' : 1})}} - {{if data.malfStatus == 1}} - {{:helper.link('Override Programming', 'script', {'malfhack' : 1})}} - {{else data.malfStatus > 1}} -
APC Hacked
- {{/if}} -
- {{/if}} - -
-{{/if}} \ No newline at end of file diff --git a/nano/templates/appearance_changer.tmpl b/nano/templates/appearance_changer.tmpl deleted file mode 100644 index 1111add5c5..0000000000 --- a/nano/templates/appearance_changer.tmpl +++ /dev/null @@ -1,86 +0,0 @@ -{{if data.change_race}} -
-
- Species: -
-
- {{for data.species}} - {{:helper.link(value.specimen, null, { 'race' : value.specimen}, null, data.specimen == value.specimen ? 'selected' : null)}} - {{/for}} -
-
-{{/if}} - -{{if data.change_gender}} -
-
- Biological Gender: -
-
- {{for data.genders}} - {{:helper.link(value.gender_name, null, { 'gender' : value.gender_key}, null, data.gender == value.gender_key ? 'selected' : null)}} - {{/for}} -
- -
-
- Gender Identity: -
-
- {{for data.id_genders}} - {{:helper.link(value.gender_name, null, { 'gender_id' : value.gender_key}, null, data.gender_id == value.gender_key ? 'selected' : null)}} - {{/for}} -
-
-{{/if}} - -{{if data.change_eye_color || data.change_skin_tone || data.change_skin_color || data.change_hair_color || data.change_facial_hair_color}} -
-
- Colors: -
-
- {{if data.change_eye_color}} - {{:helper.link('Change eye color', null, { 'eye_color' : 1})}} - {{/if}} - {{if data.change_skin_tone}} - {{:helper.link('Change skin tone', null, { 'skin_tone' : 1})}} - {{/if}} - {{if data.change_skin_color}} - {{:helper.link('Change skin color', null, { 'skin_color' : 1})}} - {{/if}} - {{if data.change_hair_color}} - {{:helper.link('Change hair color', null, { 'hair_color' : 1})}} - {{/if}} - {{if data.change_facial_hair_color}} - {{:helper.link('Change facial hair color', null, { 'facial_hair_color' : 1})}} - {{/if}} -
-
-{{/if}} - -{{if data.change_hair}} -
-
- Hair styles: -
-
- {{for data.hair_styles}} - {{:helper.link(value.hairstyle, null, { 'hair' : value.hairstyle}, null, data.hair_style == value.hairstyle ? 'selected' : null)}} - {{/for}} -
-
-{{/if}} - -{{if data.change_facial_hair}} -
-
- Facial hair styles: -
-
- {{for data.facial_hair_styles}} - {{:helper.link(value.facialhairstyle, null, { 'facial_hair' : value.facialhairstyle}, null, data.facial_hair_style == value.facialhairstyle ? 'selected' : null)}} - {{/for}} -
-
-{{/if}} diff --git a/nano/templates/atmo_control.tmpl b/nano/templates/atmo_control.tmpl deleted file mode 100644 index d3c61758e7..0000000000 --- a/nano/templates/atmo_control.tmpl +++ /dev/null @@ -1,224 +0,0 @@ - -{{if data.sensors}} - {{for data.sensors}} - {{if value.sensor_data}} -
-
{{:value.long_name}}
- {{if value.sensor_data.pressure}} -
-
Pressure:
-
{{:value.sensor_data.pressure}} kPa
-
- {{/if}} - {{if value.sensor_data.temperature}} -
-
Temperature:
-
{{:value.sensor_data.temperature}} K
-
- {{/if}} - {{if value.sensor_data.oxygen || value.sensor_data.nitrogen || value.sensor_data.carbon_dioxide || value.sensor_data.phoron}} -
-
Gas Composition:
- {{if value.sensor_data.oxygen}} -
{{:value.sensor_data.oxygen}}% O2
- {{/if}} - {{if value.sensor_data.nitrogen}} -
{{:value.sensor_data.nitrogen}}% N
- {{/if}} - {{if value.sensor_data.carbon_dioxide}} -
{{:value.sensor_data.carbon_dioxide}}% CO2
- {{/if}} - {{if value.sensor_data.phoron}} -
{{:value.sensor_data.phoron}}% TX
- {{/if}} -
- {{/if}} -
- {{else}} -
-
{{:value.long_name}} can not be found!
-
- {{/if}} - {{/for}} -{{else}} -
- No sensors connected. -
-{{/if}} - -{{if data.tanks || data.core}} -

- {{if data.tanks}} - Tank Control System - {{else data.core}} - Core Cooling Control System - {{/if}} -

- - {{if data.input_info}} -
-
- {{if data.tanks}} - Input: - {{else data.core}} - Coolant Input: - {{/if}} -
-
- {{if data.input_info.power}} - Injecting - {{else}} - On Hold - {{/if}} -
-
-
-
Flow Rate Limit:
-
{{:data.input_info.volume_rate}} L/s
-
-
-
Command:
- {{:helper.link('Toggle Power', 'power', {'in_toggle_injector' : 1})}} - {{:helper.link('Set Flow Rate', 'pencil', {'in_set_flowrate' : 1})}} - {{:helper.link('Refresh', 'refresh', {'in_refresh_status' : 1})}} -
- {{else}} -
-
ERROR: Can not find input port
- {{:helper.link('Search', 'search', {'in_refresh_status' : 1})}} -
- {{/if}} -
-
- Flow Rate Limit: -
-
- {{:helper.link('100', 'minus', {'adj_input_flow_rate' : -100})}} - {{:helper.link('10', 'minus', {'adj_input_flow_rate' : -10})}} - {{:helper.link('1', 'minus', {'adj_input_flow_rate' : -1})}} - {{:helper.link('0.1', 'minus', {'adj_input_flow_rate' : -0.1})}} -
 {{:data.input_flow_setting}} L/s 
- {{:helper.link('0.1', 'plus', {'adj_input_flow_rate' : 0.1})}} - {{:helper.link('1', 'plus', {'adj_input_flow_rate' : 1})}} - {{:helper.link('10', 'plus', {'adj_input_flow_rate' : 10})}} - {{:helper.link('100', 'plus', {'adj_input_flow_rate' : 100})}} -
-
- - {{if data.output_info}} -
-
- {{if data.tanks}} - Output: - {{else data.core}} - Core Outpump: - {{/if}} -
-
- {{if data.output_info.power}} - Open - {{else}} - On Hold - {{/if}} -
-
-
- {{if data.tanks}} -
Max Output Pressure:
-
{{:data.output_info.output_pressure}} kPa
- {{else data.core}} -
Min Core Pressure:
-
{{:data.output_info.pressure_limit}} kPa
- {{/if}} -
-
-
Command:
- {{:helper.link('Toggle Power', 'power', {'out_toggle_power' : 1})}} - {{:helper.link('Set Pressure', 'pencil', {'out_set_pressure' : 1})}} - {{:helper.link('Refresh', 'refresh', {'out_refresh_status' : 1})}} -
- {{else}} -
-
ERROR: Can not find output port
- {{:helper.link('Search', 'search', {'out_refresh_status' : 1})}} -
- {{/if}} - -
- {{if data.tanks}} -
- Max Output Pressure Set: -
-
- {{:helper.link('1000', 'minus', {'adj_pressure' : -1000})}} - {{:helper.link('100', 'minus', {'adj_pressure' : -100})}} - {{:helper.link('10', 'minus', {'adj_pressure' : -10})}} - {{:helper.link('1', 'minus', {'adj_pressure' : -1})}} -
 {{:data.pressure_setting}} kPa 
- {{:helper.link('1', 'plus', {'adj_pressure' : 1})}} - {{:helper.link('10', 'plus', {'adj_pressure' : 10})}} - {{:helper.link('100', 'plus', {'adj_pressure' : 100})}} - {{:helper.link('1000', 'plus', {'adj_pressure' : 1000})}} -
- {{else data.core}} -
- Min Core Pressure Set: -
-
- {{:helper.link('100', 'minus', {'adj_pressure' : -100})}} - {{:helper.link('50', 'minus', {'adj_pressure' : -50})}} - {{:helper.link('10', 'minus', {'adj_pressure' : -10})}} - {{:helper.link('1', 'minus', {'adj_pressure' : -1})}} -
 {{:data.pressure_setting}} kPa 
- {{:helper.link('1', 'plus', {'adj_pressure' : 1})}} - {{:helper.link('10', 'plus', {'adj_pressure' : 10})}} - {{:helper.link('50', 'plus', {'adj_pressure' : 50})}} - {{:helper.link('100', 'plus', {'adj_pressure' : 100})}} -
- {{/if}} -
-{{/if}} - -{{if data.fuel}} -

Fuel Injection System

- - {{if data.device_info}} -
-
- Status: -
-
- {{if data.device_info.power}} - Injecting - {{else}} - On Hold - {{/if}} -
{{:helper.link('Refresh', 'refresh', {'refresh_status' : 1})}}
-
-
-
-
Rate:
-
{{:data.device_info.volume_rate}} L/s
-
-
-
Automated Fuel Injection:
- {{if data.automation}} - {{:helper.link('Engaged', 'check', {'toggle_automation' : 1})}} -
Injector Controls Locked Out
- {{else}} - {{:helper.link('Disengaged', 'close', {'toggle_automation' : 1})}} -
Injector:
- {{:helper.link('Toggle Power', 'power', {'toggle_injector' : 1})}} - {{:helper.link('Inject (1 Cycle)', 'syringe', {'injection' : 1})}} - {{/if}} -
- {{else}} -
-
ERROR: Can not find device
- {{:helper.link('Search', 'search', {'refresh_status' : 1})}} -
- {{/if}} -{{/if}} diff --git a/nano/templates/atmos_alert.tmpl b/nano/templates/atmos_alert.tmpl deleted file mode 100644 index 92946e8d31..0000000000 --- a/nano/templates/atmos_alert.tmpl +++ /dev/null @@ -1,18 +0,0 @@ -

Priority Alerts

-{{for data.priority_alarms}} -
- {{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}} -
-{{empty}} - No priority alerts detected. -{{/for}} - -

Minor Alerts

-{{for data.minor_alarms}} -
- {{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}} -
-{{empty}} - No minor alerts detected. -{{/for}} - diff --git a/nano/templates/atmos_control.tmpl b/nano/templates/atmos_control.tmpl deleted file mode 100644 index ac50e3fbdf..0000000000 --- a/nano/templates/atmos_control.tmpl +++ /dev/null @@ -1,10 +0,0 @@ -{{if data.map_levels.length}} -
- {{:helper.link('Show Air Alarms On Map', 'pin-s', {'showMap' : 1})}} -
-{{/if}} -
- {{for data.alarms}} - {{:helper.link(value.name, null, {'alarm' : value.ref}, null, value.danger == 2 ? 'redButton' : (value.danger == 1 ? 'yellowButton' : null))}} - {{/for}} -
diff --git a/nano/templates/atmos_control_map_content.tmpl b/nano/templates/atmos_control_map_content.tmpl deleted file mode 100644 index 931ddb974c..0000000000 --- a/nano/templates/atmos_control_map_content.tmpl +++ /dev/null @@ -1,13 +0,0 @@ - -{{for data.alarms}} - {{if value.z == config.mapZLevel}} -
- -
- {{/if}} -{{/for}} diff --git a/nano/templates/atmos_control_map_header.tmpl b/nano/templates/atmos_control_map_header.tmpl deleted file mode 100644 index 7fea71a965..0000000000 --- a/nano/templates/atmos_control_map_header.tmpl +++ /dev/null @@ -1,20 +0,0 @@ - -{{:helper.link('Show List', 'script', {'showMap' : 0})}} -{{if data.map_levels.length > 1}} -
- Z Level:  - {{for data.map_levels }} - {{:helper.link(value, null, {'mapZLevel' : value}, null, config.mapZLevel == value ? 'selected' : null)}} - {{/for}} -
-{{/if}} -
- Zoom Level:  - - - - -
diff --git a/nano/templates/body_designer.tmpl b/nano/templates/body_designer.tmpl deleted file mode 100644 index 43b23af8f4..0000000000 --- a/nano/templates/body_designer.tmpl +++ /dev/null @@ -1,129 +0,0 @@ - -{{:data.temp}} - -{{if data.disk}} - {{:helper.link('Save To Disk', 'disk', {'savetodisk' : 1}, data.activeBodyRecord ? null : 'linkOff')}} - {{:helper.link('Load From Disk', 'folder-open', {'loadfromdisk' : 1}, data.diskStored ? null : 'linkOff')}} - {{:helper.link('Eject Disk', 'eject', {'ejectdisk' : 1})}} -{{/if}} - - - - -{{if data.menu == 1}} - -

Database Functions

-
- {{:helper.link('View Individual Body Records', 'list', {'menu' : 2})}} -
-
- {{:helper.link('View Stock Body Records', 'list', {'menu' : 3})}} -
- - -{{else data.menu == 2}} -

Current body records

- {{:helper.link('Back', 'arrowreturn-1-w', {'menu' : 1})}} -
- {{for data.bodyrecords}} - {{:helper.link(value.name, 'document', {'view_brec' : value.recref})}} - {{/for}} -
- - -{{else data.menu == 3}} -

Stock body records

- {{:helper.link('Back', 'arrowreturn-1-w', {'menu' : 1})}} -
- {{for data.stock_bodyrecords}} - {{:helper.link(value, 'document', {'view_stock_brec' : value})}} - {{/for}} -
- - -{{else data.menu == 4}} -

Selected Body Record

-
{{:helper.link('Back', 'arrowreturn-1-w', {'menu' : 1})}}
- - {{if data.activeBodyRecord}} -
-
Name:
-
{{:data.activeBodyRecord.real_name}}
-
-
-
Species:
-
{{:data.activeBodyRecord.speciesname}}
-
-
-
Bio. Sex:
-
{{:helper.link(data.activeBodyRecord.gender, null, {'bio_gender' : 1})}}
-
-
-
Synthetic:
-
{{:data.activeBodyRecord.synthetic}}
-
-
-
Mind compat.:
-
{{:data.activeBodyRecord.locked}}
-
{{:helper.link('View OOC Notes', null, {'boocnotes' : 1}, data.activeBodyRecord.booc ? null : 'linkOff')}}
-
- -
-
- -
-
-
-
Scale:
-
{{:helper.link(data.activeBodyRecord.scale, null, {'size_multiplier' : 1})}}
-
- - {{props data.activeBodyRecord.styles}} -
-
{{:key}}:
-
- {{if value.styleHref}} - - {{:helper.link(value.style, null, (a={},a[value.styleHref]=1,a))}} - {{/if}} - {{if value.colorHref}} - {{:helper.link(value.color, null, (a={},a[value.colorHref]=1,a))}} -
 
- {{/if}} -
-
- {{/props}} - -
-
-
Body Markings
-
- {{:helper.link('Add Marking', 'plus', {'marking_style' : 1})}} -
-
- {{props data.activeBodyRecord.markings}} -
- {{:key}}  - - {{:helper.link('', 'minus', {'marking_remove' : key})}} -
- {{props}} -
- {{else}} -
ERROR: Record not found.
- {{/if}} - - -{{else data.menu == 6}} -

Body OOC Notes (This is OOC!)

-
{{:helper.link('Back', 'arrowreturn-1-w', {'menu' : 4})}}
- {{if data.activeBodyRecord}} -
Notes:
-
{{:data.activeBodyRecord.booc}}
- {{else}} -
ERROR: Record not found.
- {{/if}} - -{{/if}} -
{{:JSON.stringify(data, null, 2)}}
diff --git a/nano/templates/canister.tmpl b/nano/templates/canister.tmpl deleted file mode 100644 index e4033eb016..0000000000 --- a/nano/templates/canister.tmpl +++ /dev/null @@ -1,83 +0,0 @@ -

Tank Status

-
-
- Tank Label: -
-
-
{{:data.name}}
{{:helper.link('Relabel', 'pencil', {'relabel' : 1}, data.canLabel ? null : 'disabled')}} -
-
- -
-
- Tank Pressure: -
-
- {{:data.tankPressure}} kPa -
-
- -
-
- Port Status: -
-
- {{:data.portConnected ? 'Connected' : 'Disconnected'}} -
-
- -

Holding Tank Status

-{{if data.hasHoldingTank}} -
-
- Tank Label: -
-
-
{{:data.holdingTank.name}}
{{:helper.link('Eject', 'eject', {'remove_tank' : 1})}} -
-
- -
-
- Tank Pressure: -
-
- {{:data.holdingTank.tankPressure}} kPa -
-
-{{else}} -
No holding tank inserted.
-
 
-{{/if}} - - -

Release Valve Status

-
-
- Release Pressure: -
-
- {{:helper.displayBar(data.releasePressure, data.minReleasePressure, data.maxReleasePressure)}} -
- {{:helper.link('-', null, {'pressure_adj' : -1000}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -100}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -10}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -1}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}} -
 {{:data.releasePressure}} kPa 
- {{:helper.link('+', null, {'pressure_adj' : 1}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 10}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 100}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 1000}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} -
-
-
- -
-
- Release Valve: -
-
- {{:helper.link('Open', 'unlocked', {'toggle' : 1}, data.valveOpen ? 'selected' : null)}}{{:helper.link('Close', 'locked', {'toggle' : 1}, data.valveOpen ? null : 'selected')}} -
-
- diff --git a/nano/templates/crew_monitor.tmpl b/nano/templates/crew_monitor.tmpl deleted file mode 100644 index 2dbc65d36d..0000000000 --- a/nano/templates/crew_monitor.tmpl +++ /dev/null @@ -1,32 +0,0 @@ - - - -{{if data.map_levels.length}} - {{:helper.link('Show Tracker Map', 'pin-s', {'showMap' : 1})}} -{{/if}} -
- {{for data.crewmembers}} - {{if value.sensor_type == 1}} - {{if data.isAI}}{{/if}} - {{else value.sensor_type == 2}} - {{if data.isAI}}{{/if}} - {{else value.sensor_type == 3}} - {{if data.isAI}}{{/if}} - {{/if}} - {{/for}} -
{{:value.name}} ({{:value.assignment}}){{:value.dead ? "Deceased" : "Living"}}Not Available{{:helper.link('Track', null, {}, 'disabled')}}
{{:value.name}} ({{:value.assignment}}){{:value.dead ? "Deceased" : "Living"}} ({{:value.oxy}}/{{:value.tox}}/{{:value.fire}}/{{:value.brute}})Not Available{{:helper.link('Track', null, {}, 'disabled')}}
{{:value.name}} ({{:value.assignment}}){{:value.dead ? "Deceased" : "Living"}} ({{:value.oxy}}/{{:value.tox}}/{{:value.fire}}/{{:value.brute}}){{:value.area}}({{:value.x}}, {{:value.y}}, {{:value.z}}){{:helper.link('Track', null, {'track' : value.ref})}}
diff --git a/nano/templates/crew_monitor_map_content.tmpl b/nano/templates/crew_monitor_map_content.tmpl deleted file mode 100644 index 432649926c..0000000000 --- a/nano/templates/crew_monitor_map_content.tmpl +++ /dev/null @@ -1,13 +0,0 @@ - -{{for data.crewmembers}} - {{if value.sensor_type == 3 && value.z == config.mapZLevel}} -
- -
- {{/if}} -{{/for}} diff --git a/nano/templates/crew_monitor_map_header.tmpl b/nano/templates/crew_monitor_map_header.tmpl deleted file mode 100644 index 2ec9485491..0000000000 --- a/nano/templates/crew_monitor_map_header.tmpl +++ /dev/null @@ -1,20 +0,0 @@ - -{{:helper.link('Show Detail List', 'script', {'showMap' : 0})}} -{{if data.map_levels.length > 1}} -
- Z Level:  - {{for data.map_levels }} - {{:helper.link(value, null, {'mapZLevel' : value}, null, config.mapZLevel == value ? 'selected' : null)}} - {{/for}} -
-{{/if}} -
- Zoom Level:  - - - - -
\ No newline at end of file diff --git a/nano/templates/disease_splicer.tmpl b/nano/templates/disease_splicer.tmpl deleted file mode 100644 index d2e874afe6..0000000000 --- a/nano/templates/disease_splicer.tmpl +++ /dev/null @@ -1,125 +0,0 @@ -
-
- {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}} -
-
- -{{if data.busy}} -
The Splicer is currently busy.
-
-
{{:data.busy}}
-
-

- Thank you for your patience! -

-{{else}} -
-

Virus Dish

-
-
- {{:helper.link('Eject Dish', 'eject', { 'eject' : 1 }, data.dish_inserted ? null : 'disabled')}} -
- -
-
- Growth Density: -
-
- {{:helper.displayBar(data.growth, 0, 100, (data.growth >= 50) ? 'good' : data.growth >= 25 ? 'average' : 'bad', data.growth + '%' )}} -
-
- -
-
- {{if !data.info}} -
- Symptoms: -
- {{/if}} -
- {{if data.info}} - {{:data.info}} - {{else}} - {{for data.effects}} -
-
- ({{:value.stage}}) {{:value.name}} - {{if value.badness > 1}} - Dangerous - {{/if}} -
-
- {{/for}} - {{/if}} -
-
- {{if data.affected_species && !data.info}} -
-
- Affected Species: -
-
- {{:data.affected_species}} -
-
- {{/if}} -
- {{if data.effects}} -
- CAUTION: Reverse engineering will destroy the viral sample. -
-
-
- Reverse Engineering: -
-
- {{for data.effects}} - {{:helper.link(value.stage, 'transferthick-e-w', { 'grab' : value.reference })}} - {{/for}} -
-
- {{:helper.link('Species', 'transferthick-e-w', { 'affected_species' : 1 })}} -
-
- {{/if}} - -
-

Storage

-
- -
-
- Memory Buffer: -
-
- {{if data.buffer}} - {{:data.buffer.name}} ({{:data.buffer.stage}}) - {{else}} - {{if data.species_buffer}} - {{:data.species_buffer}} - {{else}} - Empty - {{/if}} - {{/if}} -
-
- {{:helper.link('Save To Disk', 'disk', { 'disk' : 1 }, (data.buffer || data.species_buffer) ? null : 'disabled')}} - {{if data.species_buffer}} - {{:helper.link('Splice Species', 'pencil', { 'splice' : 5 }, (data.species_buffer && !data.info) ? null : 'disabled')}} - {{else data.buffer}} - {{:helper.link('Splice #1', 'pencil', { 'splice' : 1 }, data.buffer.stage > 1 ? 'disabled' : null)}} - {{:helper.link('Splice #2', 'pencil', { 'splice' : 2 }, data.buffer.stage > 2 ? 'disabled' : null)}} - {{:helper.link('Splice #3', 'pencil', { 'splice' : 3 }, data.buffer.stage > 3 ? 'disabled' : null)}} - {{:helper.link('Splice #4', 'pencil', { 'splice' : 4 }, data.buffer.stage > 4 ? 'disabled' : null)}} - {{/if}} -{{/if}} - - - - - - - - - - diff --git a/nano/templates/dish_incubator.tmpl b/nano/templates/dish_incubator.tmpl deleted file mode 100644 index ae887e6986..0000000000 --- a/nano/templates/dish_incubator.tmpl +++ /dev/null @@ -1,123 +0,0 @@ -
-
- {{:helper.link('Close', 'gear', {'close' : '1'}, null, 'fixedLeft')}} -
-
- -
-

Environmental Conditions

-
-
-
- Power: -
-
- {{:helper.link('On', 'power', { 'power' : 1 }, !data.dish_inserted ? 'disabled' : data.on ? 'selected' : null)}}{{:helper.link('Off', 'close', { 'power' : 1 }, data.on ? null : 'selected')}} -
-
-
- {{:helper.link('Add Radiation', 'radiation', {'rad' : 1})}} - {{:helper.link('Flush System', 'trash', {'flush' : 1}, data.system_in_use ? null : 'disabled')}} -
- -
-
-
- Virus Food: -
-
- {{:helper.displayBar(data.food_supply, 0, 100, 'good', data.food_supply)}} -
-
-
-
- Radiation Level: -
-
- {{:helper.displayBar(data.radiation, 0, 100, (data.radiation >= 50) ? 'bad' : (data.growth >= 25) ? 'average' : 'good')}} -
- {{:helper.formatNumber(data.radiation * 10000)}} µSv -
-
-
-
- Toxicity: -
-
- {{:helper.displayBar(data.toxins, 0, 100, (data.toxins >= 50) ? 'bad' : (data.toxins >= 25) ? 'average' : 'good', data.toxins + '%')}} -
-
-
- -
-

Chemicals

-
-
- {{:helper.link('Eject Chemicals', 'eject', { 'ejectchem' : 1 }, data.chemicals_inserted ? null : 'disabled')}} - {{:helper.link('Breed Virus', 'circle-arrow-s', { 'virus' : 1 }, data.can_breed_virus ? null : 'disabled')}} -
- -{{if data.chemicals_inserted}} -
-
- Volume: -
-
- {{:helper.displayBar(data.chemical_volume, 0, data.max_chemical_volume, 'good', data.chemical_volume + ' / ' + data.max_chemical_volume)}} -
-
-
-
- Breeding Environment: -
-
- - {{:!data.dish_inserted ? 'N/A' : data.can_breed_virus ? 'Suitable' : 'No hemolytic samples detected'}} - - {{if data.blood_already_infected}} -
- CAUTION: Viral infection detected in blood sample. - {{/if}} -
-
-{{else}} -
- No chemicals inserted. -
-{{/if}} - -
-

Virus Dish

-
-
- {{:helper.link('Eject Dish', 'eject', {'ejectdish' : 1}, data.dish_inserted ? null : 'disabled')}} -
- -{{if data.dish_inserted}} - {{if data.virus}} -
-
- Growth Density: -
-
- {{:helper.displayBar(data.growth, 0, 100, (data.growth >= 50) ? 'good' : (data.growth >= 25) ? 'average' : 'bad', data.growth + '%' )}} -
-
-
-
- Infection Rate: -
-
- {{:data.analysed ? data.infection_rate : "Unknown"}} -
-
- {{else}} -
- No virus detected. -
- {{/if}} -{{else}} -
- No dish loaded. -
-{{/if}} diff --git a/nano/templates/docking_airlock_console.tmpl b/nano/templates/docking_airlock_console.tmpl deleted file mode 100644 index 08d4dbf0e4..0000000000 --- a/nano/templates/docking_airlock_console.tmpl +++ /dev/null @@ -1,96 +0,0 @@ -
-
-
- Docking Port Status: -
- {{if data.docking_status == "docked"}} -
- {{if !data.override_enabled}} - DOCKED - {{else}} - DOCKED-OVERRIDE ENABLED - {{/if}} - - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - -
- {{else data.docking_status == "docking"}} -
- {{if !data.override_enabled}} - DOCKING - {{else}} - DOCKING-OVERRIDE ENABLED - {{/if}} - - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - -
- {{else data.docking_status == "undocking"}} -
- {{if !data.override_enabled}} - UNDOCKING - {{else}} - UNDOCKING-OVERRIDE ENABLED - {{/if}} - - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - -
- {{else data.docking_status == "undocked"}} -
- {{if !data.override_enabled}} - NOT IN USE - {{else}} - OVERRIDE ENABLED - {{/if}} - - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - -
- {{else}} - ERROR - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - {{/if}} -
-
-
-
-
- Chamber Pressure: -
-
- {{:helper.displayBar(data.chamber_pressure, 0, 200, (data.chamber_pressure < 80 || data.chamber_pressure > 120) ? 'bad' : (data.chamber_pressure < 95 || data.chamber_pressure > 110) ? 'average' : 'good')}} -
- {{:data.chamber_pressure}} kPa -
-
-
-
-
-
-
- {{:helper.link('Cycle to Exterior', 'arrowthickstop-1-w', {'command' : 'cycle_ext'}, (data.processing || data.airlock_disabled) ? 'disabled' : null)}} - {{:helper.link('Cycle to Interior', 'arrowthickstop-1-e', {'command' : 'cycle_int'}, (data.processing || data.airlock_disabled) ? 'disabled' : null)}} -
-
- {{if data.airlock_disabled}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, 'disabled', null)}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, 'disabled', null)}} - {{else}} - {{if data.interior_status.state == "open"}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, 'redButton')}} - {{else}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, data.processing ? 'yellowButton' : null)}} - {{/if}} - {{if data.exterior_status.state == "open"}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, 'redButton')}} - {{else}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, data.processing ? 'yellowButton' : null)}} - {{/if}} - {{/if}} -
-
-
- {{:helper.link('Abort', 'cancel', {'command' : 'abort'}, (data.processing && !data.airlock_disabled) ? null : 'disabled', (data.processing && !data.airlock_disabled) ? 'redButton' : null)}} -
-
\ No newline at end of file diff --git a/nano/templates/door_access_console.tmpl b/nano/templates/door_access_console.tmpl deleted file mode 100644 index 2e5c81cb7e..0000000000 --- a/nano/templates/door_access_console.tmpl +++ /dev/null @@ -1,42 +0,0 @@ -
-
-
- Exterior Door Status: -
-
- {{if data.exterior_status.state == "closed"}} - Locked - {{else}} - Open - {{/if}} -
-
-
-
- Interior Door Status: -
-
- {{if data.interior_status.state == "closed"}} - Locked - {{else}} - Open - {{/if}} -
-
-
-
-
-
- {{if data.exterior_status.state == "open"}} - {{:helper.link('Lock Exterior Door', 'alert', {'command' : 'force_ext'}, data.processing ? 'disabled' : null)}} - {{else}} - {{:helper.link('Cycle to Exterior', 'arrowthickstop-1-w', {'command' : 'cycle_ext_door'}, data.processing ? 'disabled' : null)}} - {{/if}} - {{if data.interior_status.state == "open"}} - {{:helper.link('Lock Interior Door', 'alert', {'command' : 'force_int'}, data.processing ? 'disabled' : null)}} - {{else}} - {{:helper.link('Cycle to Interior', 'arrowthickstop-1-e', {'command' : 'cycle_int_door'}, data.processing ? 'disabled' : null)}} - {{/if}} -
-
-
\ No newline at end of file diff --git a/nano/templates/escape_pod_berth_console.tmpl b/nano/templates/escape_pod_berth_console.tmpl deleted file mode 100644 index 434fa386cf..0000000000 --- a/nano/templates/escape_pod_berth_console.tmpl +++ /dev/null @@ -1,42 +0,0 @@ -
-
-
- Escape Pod Status: -
-
- {{if data.docking_status == "docked"}} - {{if data.armed}} - ARMED - {{else}} - SYSTEMS OK - {{/if}} - {{else data.docking_status == "undocking"}} - EJECTING-STAND CLEAR! - {{else data.docking_status == "undocked"}} - POD EJECTED - {{else data.docking_status == "docking"}} - INITIALIZING... - {{else}} - ERROR - {{/if}} -
-
-
-
-
-
- {{if data.armed}} - {{if data.docking_status == "docked"}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - {{else}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', data.override_enabled ? 'redButton' : null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : 'yellowButton')}} - {{/if}} - {{else}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, 'disabled', null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, 'disabled', null)}} - {{/if}} -
-
-
\ No newline at end of file diff --git a/nano/templates/escape_pod_console.tmpl b/nano/templates/escape_pod_console.tmpl deleted file mode 100644 index aa24d3a9ce..0000000000 --- a/nano/templates/escape_pod_console.tmpl +++ /dev/null @@ -1,95 +0,0 @@ -
-
-
- Escape Pod Status: -
-
- {{if data.docking_status == "docked"}} - {{if data.is_armed}} - ARMED - {{else}} - SYSTEMS OK - {{/if}} - {{else data.docking_status == "undocking"}} - EJECTING - {{else data.docking_status == "undocked"}} - POD EJECTED - {{else data.docking_status == "docking"}} - DOCKING - {{else}} - ERROR - {{/if}} -
-
-
-
-
-
- Docking Hatch: -
-
- {{if data.docking_status == "docked"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed"}} - CLOSED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "docking"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "undocking"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "undocked"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else}} - ERROR - {{/if}} -
-
-
-
-
-
- {{if data.docking_status == "docked"}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - {{else}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', data.override_enabled ? 'redButton' : null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : 'yellowButton')}} - {{/if}} -
-
-
-
-
-
- {{:helper.link('ARM', 'alert', {'command' : 'manual_arm'}, data.is_armed ? 'disabled' : null, data.is_armed ? 'redButton' : 'yellowButton')}} - {{:helper.link('MANUAL EJECT', 'alert', {'command' : 'force_launch'}, data.can_force ? null : 'disabled', data.can_force ? 'yellowButton' : null)}} -
-
-
diff --git a/nano/templates/exonet_node.tmpl b/nano/templates/exonet_node.tmpl deleted file mode 100644 index df075c8b89..0000000000 --- a/nano/templates/exonet_node.tmpl +++ /dev/null @@ -1,49 +0,0 @@ - - -

Status

-
-
- Power: -
-
- {{:helper.link('On', 'power', {'toggle_power' : 1}, data.on ? 'selected' : null)}}{{:helper.link('Off', 'close', {'toggle_power' : 1}, data.on ? null : 'selected', data.on ? 'redButton' : null)}} -
-
- -

Ports

-
-
- Incoming PDA Messages: -
-
- {{:helper.link('Open', 'check', {'toggle_PDA_port' : 1}, data.allowPDAs ? 'selected' : null)}}{{:helper.link('Close', 'close', {'toggle_PDA_port' : 1}, data.allowPDAs ? null : 'selected')}} -
-
-
-
- Incoming Communicators: -
-
- {{:helper.link('Open', 'check', {'toggle_communicator_port' : 1}, data.allowCommunicators ? 'selected' : null)}}{{:helper.link('Close', 'close', {'toggle_communicator_port' : 1}, data.allowCommunicators ? null : 'selected')}} -
-
-
-
- Incoming Newscaster Content: -
-
- {{:helper.link('Open', 'check', {'toggle_newscaster_port' : 1}, data.allowNewscasters ? 'selected' : null)}}{{:helper.link('Close', 'close', {'toggle_newscaster_port' : 1}, data.allowNewscasters ? null : 'selected')}} -
-
- -

Logging

-
- {{for data.logs}} -
- {{:value}} -
- {{/for}} -
diff --git a/nano/templates/freezer.tmpl b/nano/templates/freezer.tmpl deleted file mode 100644 index fad41bad9f..0000000000 --- a/nano/templates/freezer.tmpl +++ /dev/null @@ -1,62 +0,0 @@ -
-
- Status: -
-
- {{:helper.link('On', 'power', {'toggleStatus' : 1}, data.on ? 'selected' : null)}}{{:helper.link('Off', 'close', {'toggleStatus' : 1}, data.on ? null : 'selected')}} -
-
- -
-
- Power Level: -
-
- {{:helper.link('1', null, {'setPower' : 20}, (data.powerSetting == 20)? 'selected' : null)}} - {{:helper.link('2', null, {'setPower' : 40}, (data.powerSetting == 40)? 'selected' : null)}} - {{:helper.link('3', null, {'setPower' : 60}, (data.powerSetting == 60)? 'selected' : null)}} - {{:helper.link('4', null, {'setPower' : 80}, (data.powerSetting == 80)? 'selected' : null)}} - {{:helper.link('5', null, {'setPower' : 100}, (data.powerSetting == 100)? 'selected' : null)}} -
-
- -
-
- Gas Pressure: -
-
- {{:data.gasPressure}} kPa -
-
- -

Gas Temperature

-
-
- Current: -
-
- {{:helper.displayBar(data.gasTemperature, data.minGasTemperature, data.maxGasTemperature, data.gasTemperatureClass)}} -
- {{:data.gasTemperature}} K -
-
-
- -
-
- Target: -
-
- {{:helper.displayBar(data.targetGasTemperature, data.minGasTemperature, data.maxGasTemperature)}} -
- {{:helper.link('-', null, {'temp' : -100}, (data.targetGasTemperature > data.minGasTemperature) ? null : 'disabled')}} - {{:helper.link('-', null, {'temp' : -10}, (data.targetGasTemperature > data.minGasTemperature) ? null : 'disabled')}} - {{:helper.link('-', null, {'temp' : -1}, (data.targetGasTemperature > data.minGasTemperature) ? null : 'disabled')}} -
 {{:data.targetGasTemperature}} K 
- {{:helper.link('+', null, {'temp' : 1}, (data.targetGasTemperature < data.maxGasTemperature) ? null : 'disabled')}} - {{:helper.link('+', null, {'temp' : 10}, (data.targetGasTemperature < data.maxGasTemperature) ? null : 'disabled')}} - {{:helper.link('+', null, {'temp' : 100}, (data.targetGasTemperature < data.maxGasTemperature) ? null : 'disabled')}} -
-
-
- diff --git a/nano/templates/gas_pump.tmpl b/nano/templates/gas_pump.tmpl deleted file mode 100644 index a26d88a2cf..0000000000 --- a/nano/templates/gas_pump.tmpl +++ /dev/null @@ -1,44 +0,0 @@ -
-
- Power: -
-
- {{:helper.link(data.on? 'On' : 'Off', null, {'power' : 1})}} -
-
- -
-
- Desirable output pressure: -
-
-
- {{:helper.link('MAX', null, {'set_press' : 'max'}, null)}} - {{:helper.link('SET', null, {'set_press' : 'set'}, null)}} -
 {{:(data.pressure_set/100)}} kPa 
-
-
-
- -
-
- Load: -
-
- {{:helper.displayBar(data.last_power_draw, 0, data.max_power_draw, (data.last_power_draw < data.max_power_draw - 5) ? 'good' : 'average')}} -
- {{:data.last_power_draw}} W -
-
-
- -
-
- Flow Rate: -
-
-
- {{:(data.last_flow_rate/10)}} L/s -
-
-
\ No newline at end of file diff --git a/nano/templates/generator.tmpl b/nano/templates/generator.tmpl deleted file mode 100644 index 150884187f..0000000000 --- a/nano/templates/generator.tmpl +++ /dev/null @@ -1,142 +0,0 @@ -
-
- Total Output: -
-
- {{:helper.displayBar(data.totalOutput, 0, data.maxTotalOutput)}} -
-
- {{:helper.fixed(data.totalOutput, 1)}} kW -
-
-
-
- Thermal Output: -
-
- {{:helper.fixed(data.thermalOutput, 1)}} kW -
-
-
- -{{if data.circConnected}} - - - - - - -
-
-

Primary Circulator ({{:data.primaryDir}})

-
-
- Turbine Output: -
-
- {{:helper.fixed(data.primaryOutput, 1)}} kW -
-
-
-
- Flow Capacity: -
-
- {{:helper.fixed(data.primaryFlowCapacity, 1)}} % -
-
-
-
-
- Inlet Pressure: -
-
- {{:helper.fixed(data.primaryInletPressure, 1)}} kPa -
-
-
-
- Inlet Temperature: -
-
- {{:helper.fixed(data.primaryInletTemperature, 1)}} K -
-
-
-
-
- Outlet Pressure: -
-
- {{:helper.fixed(data.primaryOutletPressure, 1)}} kPa -
-
-
-
- Outlet Temperature: -
-
- {{:helper.fixed(data.primaryOutletTemperature, 1)}} K -
-
-
-
-
-

Secondary Circulator ({{:data.secondaryDir}})

-
-
- Turbine Output: -
-
- {{:helper.fixed(data.secondaryOutput, 1)}} kW -
-
-
-
- Flow Capacity: -
-
- {{:helper.fixed(data.secondaryFlowCapacity, 1)}} % -
-
-
-
-
- Inlet Pressure: -
-
- {{:helper.fixed(data.secondaryInletPressure, 1)}} kPa -
-
-
-
- Inlet Temperature: -
-
- {{:helper.fixed(data.secondaryInletTemperature, 1)}} K -
-
-
-
-
- Outlet Pressure: -
-
- {{:helper.fixed(data.secondaryOutletPressure, 1)}} kPa -
-
-
-
- Outlet Temperature: -
-
- {{:helper.fixed(data.secondaryOutletTemperature, 1)}} K -
-
-
-
-{{else}} -
- ERROR: Both circulators must be connected! -
-{{/if}} diff --git a/nano/templates/gravity_generator.tmpl b/nano/templates/gravity_generator.tmpl deleted file mode 100644 index ad8e686c49..0000000000 --- a/nano/templates/gravity_generator.tmpl +++ /dev/null @@ -1,45 +0,0 @@ -
-
-
- Breaker Setting: -
-
- {{if data.breaker}} - Generator Enabled - {{else}} - Generator Disabled - {{/if}} -
-
-
-
- Charge Mode: -
-
- {{if (data.breaker && data.charge_count < 100)}} - Generator CHARGING - {{else (data.breaker && data.charge_count >= 100)}} - Generator Running - {{else (!data.breaker && data.charge_count > 0)}} - Generator DISCHARGING - {{else}} - Generator Offline - {{/if}} -
-
-
-
- Charge Status: -
-
- {{:data.charge_count}}% -
-
-
-
-
-
- {{:helper.link('Toggle Breaker', 'alert', {'gentoggle' : 1}, null)}} -
-
-
\ No newline at end of file diff --git a/nano/templates/hardsuit.tmpl b/nano/templates/hardsuit.tmpl deleted file mode 100644 index deb906249b..0000000000 --- a/nano/templates/hardsuit.tmpl +++ /dev/null @@ -1,257 +0,0 @@ - - - - -{{if data.interfacelock || data.malf > 0}} -
-- HARDSUIT INTERFACE OFFLINE --
-{{else}} - {{if data.aicontrol && data.ai != 1}} -
-- HARDSUIT CONTROL OVERRIDDEN BY AI --
- {{else}} -
-
-
- Power supply -
-
- {{:helper.displayBar(data.chargestatus, 0, 50, (data.chargestatus >= 35) ? 'good' : (data.chargestatus >= 15) ? 'average' : 'bad')}} {{:data.charge}}/{{:data.maxcharge}} -
-
-
-
-
- AI control: -
-
- {{if data.aioverride}} -
ENABLED
- {{else}} -
DISABLED
- {{/if}} -
-
- {{:helper.link('Toggle', 'circle-arrow-s', {'toggle_ai_control' : 1}, null)}} -
-
-
-
- Suit status: -
-
- {{if data.sealing == 1}} -
PROCESSING
- {{else}} - {{if data.seals == 1}} -
INACTIVE
- {{else}} -
ACTIVE
- {{/if}} - {{/if}} -
-
- {{:helper.link('Toggle', 'circle-arrow-s', {'toggle_seals' : 1}, null)}} -
-
-
-
- Cover status: -
-
- {{if data.emagged || !data.securitycheck}} -
ERROR - MAINTENANCE LOCK CONTROL OFFLINE
- {{else}} - {{if data.coverlock}} -
LOCKED
- {{else}} -
UNLOCKED
- {{/if}} - {{/if}} -
-
- {{:helper.link('Toggle', 'circle-arrow-s', {'toggle_suit_lock' : 1}, null)}} -
-
-
-
- -

Hardware

-

Suit pieces

- -
-
-
- Helmet: -
-
- {{:helper.capitalizeFirstLetter(data.helmet)}} -
- {{if data.sealing != 1}} -
- {{:helper.link('Toggle', 'circle-arrow-s', {'toggle_piece' : 'helmet'}, null)}} -
- {{/if}} -
-
-
- Gauntlets: -
-
- {{:helper.capitalizeFirstLetter(data.gauntlets)}} -
- {{if data.sealing != 1}} -
- {{:helper.link('Toggle', 'circle-arrow-s', {'toggle_piece' : 'gauntlets'}, null)}} -
- {{/if}} -
-
-
- Boots: -
-
- {{:helper.capitalizeFirstLetter(data.boots)}} -
- {{if data.sealing != 1}} -
- {{:helper.link('Toggle', 'circle-arrow-s', {'toggle_piece' : 'boots'}, null)}} -
- {{/if}} -
-
-
- Chestpiece: -
-
- {{:helper.capitalizeFirstLetter(data.chest)}} -
- {{if data.sealing != 1}} -
- {{:helper.link('Toggle', 'circle-arrow-s', {'toggle_piece' : 'chest'}, null)}} -
- {{/if}} -
-
- -

System modules

- {{if data.seals == 1 || data.sealing == 1}} -

HARDSUIT SYSTEMS OFFLINE

- {{else}} -

Selected primary system: - {{if data.primarysystem}} - {{:helper.capitalizeFirstLetter(data.primarysystem)}} - {{else}} - None - {{/if}} -

- {{if data.modules}} -
- {{for data.modules}} -
-
-
-
{{:helper.capitalizeFirstLetter(value.name)}}
- {{if value.damage > 0}} -
- {{if value.damage == 1}} - (
damaged
) - {{else}} - (
destroyed
) - {{/if}} -
- {{/if}} -
-
- Engage: {{:value.engagecost}} - Activate: {{:value.activecost}} - Passive: {{:value.passivecost}} -
-
- {{:value.desc}} -
-
- {{if value.can_use == 1}} -
- {{:helper.link(value.engagestring, 'circle-arrow-s', {'interact_module' : value.index, 'module_mode' : 'engage'}, null)}} -
- {{/if}} - {{if value.can_select == 1}} -
- {{if value.name == data.primarysystem}} -
SELECTED
- {{else}} - {{:helper.link('Select', 'circle-arrow-s', {'interact_module' : value.index, 'module_mode' : 'select'}, null)}} - {{/if}} -
- {{/if}} - {{if value.can_toggle == 1}} -
- {{if value.is_active == 1}} - {{:helper.link(value.deactivatestring, 'circle-arrow-s', {'interact_module' : value.index, 'module_mode' : 'deactivate'}, null)}} - {{else}} - {{:helper.link(value.activatestring, 'circle-arrow-s', {'interact_module' : value.index, 'module_mode' : 'activate'}, null)}} - {{/if}} -
- {{/if}} -
-
-
-
- {{if value.charges}} -
Stored charges
-
Selected: {{:helper.capitalizeFirstLetter(value.chargetype)}}
- {{for value.charges :itemValue:itemIndex}} -
- {{:helper.link(helper.capitalizeFirstLetter(itemValue.caption), null, {'interact_module' : value.index, 'module_mode' : 'select_charge_type', 'charge_type' : itemValue.index}, null)}} -
- {{/for}} - {{/if}} -
-
-
- {{/for}} -
- {{else}} - None. - {{/if}} - {{/if}} - {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/isolation_centrifuge.tmpl b/nano/templates/isolation_centrifuge.tmpl deleted file mode 100644 index 4ff0272df0..0000000000 --- a/nano/templates/isolation_centrifuge.tmpl +++ /dev/null @@ -1,81 +0,0 @@ -
- {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}} - {{:helper.link('Print', 'print', { 'print' : 1 }, data.antibodies || data.pathogens ? null : 'disabled', 'fixedLeft')}} -
- -{{if data.busy}} -
The Centrifuge is currently busy.
-
-
{{:data.busy}}
-
-

- Thank you for your patience! -

-{{else}} -
-

{{:data.is_antibody_sample ? 'Antibody Sample' : 'Blood Sample'}}

-
-
- {{:helper.link('Eject Vial', 'eject', { 'action' : 'sample' }, data.sample_inserted ? null : 'disabled')}} -
- {{if data.sample_inserted}} - {{if data.antibodies || data.pathogens}} -
- {{if data.antibodies}} -
-
- Antibodies: -
-
- {{:data.antibodies}} -
-
- {{/if}} - {{if data.pathogens}} -
-
- Pathogens: -
-
- {{for data.pathogens}} -
- {{:value.name}} ({{:value.spread_type}}) -
- {{/for}} -
-
- {{/if}} -
- {{else}} -
- No antibodies or viral strains detected. -
- {{/if}} - {{else}} -
- No vial detected. -
- {{/if}} - {{if data.antibodies && !data.is_antibody_sample}} -
-
- Isolate Antibodies: -
-
- {{:helper.link(data.antibodies, 'pencil', { 'action' : 'antibody' })}} -
-
- {{/if}} - {{if data.pathogens}} -
-
- Isolate Strain: -
-
- {{for data.pathogens}} - {{:helper.link(value.name, 'pencil', { 'isolate' : value.reference })}} - {{/for}} -
-
- {{/if}} -{{/if}} diff --git a/nano/templates/mod_sec_camera.tmpl b/nano/templates/mod_sec_camera.tmpl deleted file mode 100644 index 0afb80f4b8..0000000000 --- a/nano/templates/mod_sec_camera.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -
- {{:helper.link('Show Map', 'pin-s', {'showMap' : 1})}} - {{:helper.link('Reset', 'refresh', {'reset' : 1})}} -
- -
-
Current Camera:
- {{if data.current_camera}} -
{{:data.current_camera.name}}
- {{else}} -
None
- {{/if}} -
- -
-
Networks:
-
-{{for data.networks}} - {{if value.has_access}} - {{:helper.link(value.tag, '', {'switch_network' : value.tag}, null, data.current_network == value.tag ? 'selected' : null)}} - {{else}} - {{:helper.link(value.tag, '', {}, null, data.current_network == value.tag ? 'selected' : 'redButton')}} - {{/if}} -{{/for}} -
-
Cameras:
-
-{{for data.cameras}} - {{if data.current_camera && value.name == data.current_camera.name}} - {{:helper.link(value.name, '', {'switch_camera' : value.camera}, 'selected')}} - {{else value.deact}} - {{:helper.link(value.name + " (deactivated)", '', {}, 'inactive')}} - {{else}} - {{:helper.link(value.name, '', {'switch_camera' : value.camera})}} - {{/if}} -{{/for}} diff --git a/nano/templates/mod_sec_camera_map_header.tmpl b/nano/templates/mod_sec_camera_map_header.tmpl deleted file mode 100644 index 459027797f..0000000000 --- a/nano/templates/mod_sec_camera_map_header.tmpl +++ /dev/null @@ -1,44 +0,0 @@ -
- {{:helper.link('Show Camera List', 'script', {'showMap' : 0})}} - {{:helper.link('Reset', 'refresh', {'reset' : 1})}} -
-
-
Current Camera:
- {{if data.current_camera}} -
{{:data.current_camera.name}}
- {{else}} -
None
- {{/if}} -
- -
-
- Z-Level: -
-
- {{for config.mapZLevels :zValue:zIndex}} - {{:helper.link(zValue, 'close', {'mapZLevel' : zValue}, null, config.mapZLevel == zValue ? 'selected' : null)}} - {{/for}} -
-
-
-
- Zoom Level: -
-
- - - - -
-
-
-
Networks:
-
-{{for data.networks}} - {{if value.has_access}} - {{:helper.link(value.tag, '', {'switch_network' : value.tag}, null, data.current_network == value.tag ? 'selected' : null)}} - {{else}} - {{:helper.link(value.tag, '', {}, null, data.current_network == value.tag ? 'selected' : 'redButton')}} - {{/if}} -{{/for}} \ No newline at end of file diff --git a/nano/templates/multi_docking_console.tmpl b/nano/templates/multi_docking_console.tmpl deleted file mode 100644 index 9515799644..0000000000 --- a/nano/templates/multi_docking_console.tmpl +++ /dev/null @@ -1,37 +0,0 @@ -
-
-
- Docking Port Status: -
-
- {{if data.docking_status == "docked"}} - DOCKED - {{else data.docking_status == "docking"}} - DOCKING - {{else data.docking_status == "undocking"}} - UNDOCKING - {{else data.docking_status == "undocked"}} - NOT IN USE - {{else}} - ERROR - {{/if}} -
-
-
- -{{for data.airlocks}} -
-
-
- {{:value.name}} -
-
- {{if value.override_enabled}} - OVERRIDE ENABLED - {{else}} - STATUS OK - {{/if}} -
-
-
-{{/for}} \ No newline at end of file diff --git a/nano/templates/ntnet_relay.tmpl b/nano/templates/ntnet_relay.tmpl deleted file mode 100644 index 24bd831782..0000000000 --- a/nano/templates/ntnet_relay.tmpl +++ /dev/null @@ -1,32 +0,0 @@ -{{if data.dos_crashed}} -

NETWORK BUFFERS OVERLOADED

-

Overload Recovery Mode

- This system is suffering temporary outage due to overflow of traffic buffers. Until buffered traffic is processed, all further requests will be dropped. Frequent occurences of this error may indicate insufficient hardware capacity of your network. Please contact your network planning department for instructions on how to resolve this issue. -

ADMINISTRATIVE OVERRIDE

- CAUTION - Data loss may occur - {{:helper.link('Purge buffered traffic', null, { 'restart' : 1 })}} -{{else}} -
- Relay status: -
-
- {{if data.enabled}} - {{:helper.link('ENABLED', null, { 'toggle' : 1 })}} - {{else}} - {{:helper.link('DISABLED', null, { 'toggle' : 1 })}} - {{/if}} - -
-
- Network buffer status: -
-
- {{:data.dos_overload}} / {{:data.dos_capacity}} GQ -
-
- Options: -
-
- {{:helper.link('Purge network blacklist', null, { 'purge' : 1 })}} -
-{{/if}} \ No newline at end of file diff --git a/nano/templates/omni_filter.tmpl b/nano/templates/omni_filter.tmpl deleted file mode 100644 index 672ffcfe05..0000000000 --- a/nano/templates/omni_filter.tmpl +++ /dev/null @@ -1,87 +0,0 @@ -
-
- {{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}} -
-
- {{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}} -
-
-
- {{if data.config}} - -
-
-
Port
- {{for data.ports}} -
{{:value.dir}} Port
- {{/for}} -
-
-
Input
- {{for data.ports}} -
- {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, null, value.input ? 'selected' : null)}} -
- {{/for}} -
-
-
Output
- {{for data.ports}} -
- {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} -
- {{/for}} -
-
-
Filter
- {{for data.ports}} -
- {{:helper.link(value.f_type ? value.f_type : 'None', null, {'command' : 'switch_filter', 'mode' : value.f_type, 'dir' : value.dir}, value.atmo_filter ? null : 'disabled', value.f_type ? 'selected' : null)}} -
- {{/for}} -
-
- -
- Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
-
- {{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}} -
- - {{else}} - -
-
-
Port
- {{for data.ports}} -
{{:value.dir}} Port
- {{/for}} -
-
-
Mode
- {{for data.ports}} -
- {{if value.input}} - Input - {{else value.output}} - Output - {{else value.f_type}} - {{:value.f_type}} - {{else}} - Disabled - {{/if}} -
- {{/for}} -
-
- -
- Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
- -
- Flow Rate: {{:(data.last_flow_rate/10)}} L/s -
- {{/if}} -
diff --git a/nano/templates/omni_mixer.tmpl b/nano/templates/omni_mixer.tmpl deleted file mode 100644 index 77c4573880..0000000000 --- a/nano/templates/omni_mixer.tmpl +++ /dev/null @@ -1,102 +0,0 @@ -
-
- {{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}} -
-
- {{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}} -
-
-
- {{if data.config}} - -
-
-
Port
- {{for data.ports}} -
{{:value.dir}} Port
- {{/for}} -
-
-
Input
- {{for data.ports}} -
- {{:helper.link(' ', null, value.input ? {'command' : 'switch_mode', 'mode' : 'none', 'dir' : value.dir} : {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, value.output ? 'disabled' : null, value.input ? 'selected' : null)}} -
- {{/for}} -
-
-
Output
- {{for data.ports}} -
- {{:helper.link(' ', null, value.output ? null : {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} -
- {{/for}} -
-
-
Concentration
- {{for data.ports}} -
- {{:helper.link( value.input ? helper.round(value.concentration*100)+' %' : '-', null, {'command' : 'switch_con', 'dir' : value.dir}, value.input ? null : 'disabled')}} -
- {{/for}} -
-
-
Lock
- {{for data.ports}} -
- {{:helper.link(' ', value.con_lock ? 'locked' : 'unlocked', {'command' : 'switch_conlock', 'dir' : value.dir}, value.input ? null : 'disabled', value.con_lock ? 'selected' : null)}} -
- {{/for}} -
-
- -
- Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
-
- {{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}} -
- - {{else}} - -
-
-
Port
- {{for data.ports}} -
{{:value.dir}} Port
- {{/for}} -
-
-
Mode
- {{for data.ports}} -
- {{if value.input}} - Input - {{else value.output}} - Output - {{else}} - Disabled - {{/if}} -
- {{/for}} -
-
-
Concentration
- {{for data.ports}} -
- {{if value.input}} - {{:helper.round(value.concentration*100)}} % - {{else}} - - - {{/if}} -
- {{/for}} -
-
- -
- Flow Rate: {{:(data.last_flow_rate/10)}} L/s -
- - {{/if}} -
\ No newline at end of file diff --git a/nano/templates/pacman.tmpl b/nano/templates/pacman.tmpl deleted file mode 100644 index 386358c9cc..0000000000 --- a/nano/templates/pacman.tmpl +++ /dev/null @@ -1,113 +0,0 @@ -

Status

-
-
- Generator Status: -
-
- {{if data.active}} - Online - {{else}} - Offline - {{/if}} -
-
- Generator Control: -
-
- {{if data.active}} - {{:helper.link('STOP', 'power', {'action' : "disable"})}} - {{else}} - {{:helper.link('START', 'power', {'action' : "enable"})}} - {{/if}} -
-
-

Fuel

-
-
- Fuel Type: -
-
- {{:data.fuel_type}} -
-
- Fuel Level: -
-
- {{if data.fuel_stored >= 5000}} - {{:helper.displayBar(data.fuel_stored, 0, data.fuel_capacity, 'good')}} -
{{:data.fuel_stored}}/{{:data.fuel_capacity}} cm3 - {{else data.fuel_stored >= 1000}} - {{:helper.displayBar(data.fuel_stored, 0, data.fuel_capacity, 'average')}} -
{{:data.fuel_stored}}/{{:data.fuel_capacity}} cm3 - {{else}} - {{:helper.displayBar(data.fuel_stored, 0, data.fuel_capacity, 'bad')}} -
{{:data.fuel_stored}}/{{:data.fuel_capacity}} cm3 - {{/if}} -
-
- Fuel Usage: -
-
- {{:data.fuel_usage}} cm3/s -
- {{if !data.is_ai}} -
- Control: -
-
- {{:helper.link('EJECT FUEL', 'arrowupthick-1-s', {'action' : "eject"}, data.active ? 'disabled' : null)}} -
- {{/if}} -
-

Output

-
-
- Power setting: -
-
- {{if data.output_set > data.output_safe}} - {{:data.output_set}} / {{:data.output_max}} ({{:data.output_watts}} W) - {{else}} - {{:data.output_set}} / {{:data.output_max}} ({{:data.output_watts}} W) - {{/if}} -
-
- Control: -
-
- {{:helper.link('+', null, {'action' : "higher_power"})}} - {{:helper.link('-', null, {'action' : "lower_power"})}} -
-
-

Temperature

-
-
- Temperature: -
-
- {{if data.temperature_current < (data.temperature_max * 0.8)}} - {{:helper.displayBar(data.temperature_current, 0, (data.temperature_max * 1.5), 'good')}} -
{{:data.temperature_current}} C - {{else data.temperature_current < data.temperature_max}} - {{:helper.displayBar(data.temperature_current, 0, (data.temperature_max * 1.5), 'average')}} -
{{:data.temperature_current}} C - {{else}} - {{:helper.displayBar(data.temperature_current, 0, (data.temperature_max * 1.5), 'bad')}} -
{{:data.temperature_current}} C - {{/if}} -
-
- Generator Status: -
-
- {{if data.temperature_overheat > 50}} - DANGER: CRITICAL OVERHEAT! Deactivate generator immediately! - {{else data.temperature_overheat > 20}} - WARNING: Overheating! - {{else data.temperature_overheat > 1}} - Temperature High - {{else}} - Optimal - {{/if}} -
-
\ No newline at end of file diff --git a/nano/templates/pathogenic_isolator.tmpl b/nano/templates/pathogenic_isolator.tmpl deleted file mode 100644 index 69411d858f..0000000000 --- a/nano/templates/pathogenic_isolator.tmpl +++ /dev/null @@ -1,107 +0,0 @@ -
-

Menu

-
-
- {{if !data.isolating}} - {{:helper.link('Home', 'home', {'home' : 1}, data.state == 'home' ? 'disabled' : null, 'fixedLeft')}} - {{:helper.link('List', 'note', {'list' : 1}, data.state == 'list' ? 'disabled' : null, 'fixedLeft')}} - {{:helper.link('Pathogen', 'folder-open', {'entry' : 1}, data.state == 'entry' ? 'disabled' : null, 'fixedLeft')}} - {{/if}} -
- {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}} - {{:helper.link('Print', 'print', { 'print' : 1 }, data.can_print ? null : 'disabled', 'fixedLeft')}} -
- -{{if data.isolating}} -
The Isolator is currently busy.
-
-
Isolating pathogens...
-
-

- Thank you for your patience! -

-{{else}} - {{if data.state =="home"}} -
-

Blood Sample

-
-
- {{:helper.link('Eject Syringe', 'eject', { 'eject' : 1 }, data.syringe_inserted ? null : 'disabled')}} -
- - {{if data.syringe_inserted}} -
- Pathogens: - {{if data.pathogen_pool}} - {{for data.pathogen_pool}} -
- {{:index + 1}}. #{{:value.unique_id}} {{:value.is_in_database ? "(Analysed)" : ""}}
- {{:value.name}}: {{:value.dna}} -
- {{/for}} - {{else}} - No pathogens detected. - {{/if}} -
- {{else}} -
- No syringe loaded. -
- {{/if}} - {{if data.pathogen_pool}} -
-
- Isolate Pathogens: -
-
- {{for data.pathogen_pool}} - {{:helper.link('#' + value.unique_id, 'pencil', { 'isolate' : value.reference }, null, 'fixedLeft')}} - {{/for}} -
-
-
-
- Database Lookup: -
-
- {{for data.pathogen_pool}} - {{if value.is_in_database}} - {{:helper.link('#' + value.unique_id, 'info', { 'entry' : 1, 'view' : value.record }, null, 'fixedLeft')}} - {{/if}} - {{/for}} -
-
- {{/if}} - {{else}} - {{if data.state == "list"}} -
-

View Database

-
-
- {{if data.database}} - {{for data.database}} -
-
{{:value.name}}
- {{:helper.link('Details', 'circle-arrow-s', { 'entry' : 1, 'view' : value.record }, null, 'fixedLeft')}} -
- {{/for}} - {{else}} - The viral database is empty. - {{/if}} -
- {{else}} - {{if data.state == "entry"}} - {{if data.entry}} -
-

{{:data.entry.name}}

-
-
- {{:data.entry.description}} -
- {{else}} - No virus selected. - {{/if}} - {{/if}} - {{/if}} - {{/if}} -{{/if}} diff --git a/nano/templates/phoron_airlock_console.tmpl b/nano/templates/phoron_airlock_console.tmpl deleted file mode 100644 index 8c0bb69cd7..0000000000 --- a/nano/templates/phoron_airlock_console.tmpl +++ /dev/null @@ -1,47 +0,0 @@ -
-
-
- Chamber Pressure: -
-
- {{:helper.displayBar(data.chamber_pressure, 0, 200, (data.chamber_pressure < 80 || data.chamber_pressure) > 120 ? 'bad' : (data.chamber_pressure < 95 || data.chamber_pressure > 110) ? 'average' : 'good')}} -
- {{:helper.round(data.chamber_pressure)}} kPa -
-
-
-
-
- Chamber Phoron: -
-
- {{:helper.displayBar(data.chamber_phoron, 0, 100, data.chamber_phoron >= 5 ? 'bad' : data.chamber_phoron > 0.5 ? 'average' : 'good')}} -
- {{:data.chamber_phoron < 10 ? helper.fixed(data.chamber_phoron) : helper.round(data.chamber_phoron)}} mol -
-
-
-
-
-
-
- {{:helper.link('Cycle to Exterior', 'arrowthickstop-1-w', {'command' : 'cycle_ext'}, data.processing ? 'disabled' : null)}} - {{:helper.link('Cycle to Interior', 'arrowthickstop-1-e', {'command' : 'cycle_int'}, data.processing ? 'disabled' : null)}} -
-
- {{if data.interior_status.state == "open"}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, 'redButton')}} - {{else}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, data.processing ? 'yellowButton' : null)}} - {{/if}} - {{if data.exterior_status.state == "open"}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, 'redButton')}} - {{else}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, data.processing ? 'yellowButton' : null)}} - {{/if}} -
-
-
- {{:helper.link('Abort', 'cancel', {'command' : 'abort'}, data.processing ? null : 'disabled', data.processing ? 'redButton' : null)}} -
-
\ No newline at end of file diff --git a/nano/templates/portpump.tmpl b/nano/templates/portpump.tmpl deleted file mode 100644 index 3e14aac8f9..0000000000 --- a/nano/templates/portpump.tmpl +++ /dev/null @@ -1,100 +0,0 @@ -

Pump Status

-
-
- Tank Pressure: -
-
- {{:data.tankPressure}} kPa -
-
- -
-
- Port Status: -
-
- {{:data.portConnected ? 'Connected' : 'Disconnected'}} -
-
- -
-
- Load: -
-
- {{:data.powerDraw}} W -
-
- -
-
- Cell Charge: -
-
- {{:helper.displayBar(data.cellCharge, 0, data.cellMaxCharge)}} -
-
- -

Holding Tank Status

-{{if data.hasHoldingTank}} -
-
- Tank Label: -
-
-
{{:data.holdingTank.name}}
{{:helper.link('Eject', 'eject', {'remove_tank' : 1})}} -
-
- -
-
- Tank Pressure: -
-
- {{:data.holdingTank.tankPressure}} kPa -
-
-{{else}} -
No holding tank inserted.
-
 
-{{/if}} - - -

Power Regulator Status

-
-
- Target Pressure: -
-
- {{:helper.displayBar(data.targetpressure, data.minpressure, data.maxpressure)}} -
- {{:helper.link('-', null, {'pressure_adj' : -1000}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -100}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -10}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -1}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} -
 {{:data.targetpressure}} kPa 
- {{:helper.link('+', null, {'pressure_adj' : 1}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 10}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 100}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 1000}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} -
-
-
- -
-
- Power Switch: -
-
- {{:helper.link('On', 'unlocked', {'power' : 1}, data.on ? 'selected' : null)}} {{:helper.link('Off', 'locked', {'power' : 1}, data.on ? null : 'selected')}} -
-
- -
-
- Pump Direction: -
-
- {{:helper.link('Out', 'arrowreturn-1-e', {'direction' : 1}, data.pump_dir ? 'selected' : null)}} {{:helper.link('In', 'arrowreturn-1-w', {'direction' : 1}, data.pump_dir ? null : 'selected')}} -
-
diff --git a/nano/templates/portscrubber.tmpl b/nano/templates/portscrubber.tmpl deleted file mode 100644 index c99f53344c..0000000000 --- a/nano/templates/portscrubber.tmpl +++ /dev/null @@ -1,91 +0,0 @@ -

Scrubber Status

-
-
- Tank Pressure: -
-
- {{:data.tankPressure}} kPa -
-
- -
-
- Port Status: -
-
- {{:data.portConnected ? 'Connected' : 'Disconnected'}} -
-
- -
-
- Load: -
-
- {{:data.powerDraw}} W -
-
- -
-
- Cell Charge: -
-
- {{:helper.displayBar(data.cellCharge, 0, data.cellMaxCharge)}} -
-
- -

Holding Tank Status

-{{if data.hasHoldingTank}} -
-
- Tank Label: -
-
-
{{:data.holdingTank.name}}
{{:helper.link('Eject', 'eject', {'remove_tank' : 1})}} -
-
q - -
-
- Tank Pressure: -
-
- {{:data.holdingTank.tankPressure}} kPa -
-
-{{else}} -
No holding tank inserted.
-
 
-{{/if}} - - -

Power Regulator Status

-
-
- Volume Rate: -
-
- {{:helper.displayBar(data.rate, data.minrate, data.maxrate)}} -
- {{:helper.link('-', null, {'volume_adj' : -1000}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -100}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -10}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -1}, (data.rate > data.minrate) ? null : 'disabled')}} -
 {{:data.rate}} L/s 
- {{:helper.link('+', null, {'volume_adj' : 1}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 10}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 100}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 1000}, (data.rate < data.maxrate) ? null : 'disabled')}} -
-
-
- -
-
- Power Switch: -
-
- {{:helper.link('On', 'unlocked', {'power' : 1}, data.on ? 'selected' : null)}} {{:helper.link('Off', 'locked', {'power' : 1}, data.on ? null : 'selected')}} -
-
diff --git a/nano/templates/power_monitor.tmpl b/nano/templates/power_monitor.tmpl deleted file mode 100644 index 6c9e5eee34..0000000000 --- a/nano/templates/power_monitor.tmpl +++ /dev/null @@ -1,96 +0,0 @@ -{{if data.focus}} -
- {{:helper.link('Show List', 'cancel', { 'clear' : 1})}} Sensor selected: {{:data.focus.name}} -
- {{if data.map_levels.length}} - {{:helper.link('Show APCs On Map', 'pin-s', {'showMap' : 1})}} - {{/if}} - {{if data.focus.error}} - {{:data.focus.error}} - {{else}} -

Network Information

-
- Network Load Status: -
- {{if data.focus.load_percentage >= 95}} -
DANGER: Overload
- {{else data.focus.load_percentage >= 85}} -
WARNING: High Load
- {{else}} -
Optimal
- {{/if}} -
- Network Security Status: -
- {{if data.focus.alarm}} -
WARNING: Abnormal activity detected!
- {{else}} -
Secure
- {{/if}} - -
- Load Percentage: -
-
- {{:helper.displayBar(data.focus.load_percentage, 0, 100, (data.focus.load_percentage <= 75) ? 'good' : (data.focus.load_percentage <= 90) ? 'average' : 'bad')}}{{:data.focus.load_percentage}}% -
-
- Available Power: -
-
- {{:data.focus.total_avail}} -
-
- APC Power Usage: -
-
- {{:data.focus.total_used_apc}} -
-
- Other Power Usage: -
-
- {{:data.focus.total_used_other}} -
-
- Total Usage: -
-
- {{:data.focus.total_used_all}} -
-

Sensor Readings

- -
APC NameEquipmentLightingEnvironmentCell StatusAPC Load - {{for data.focus.apc_data}} -
{{:value.name}} - {{:value.s_equipment}} - {{:value.s_lighting}} - {{:value.s_environment}} - {{if value.cell_status == "N"}} - {{:helper.link(value.cell_charge + '%', 'batt_disc', null,'disabled', 'width75btn')}} - {{else value.cell_status == "C"}} - {{:helper.link(value.cell_charge + '%', 'batt_chrg', null,'disabled', 'width75btn')}} - {{else}} - {{:helper.link(value.cell_charge + '%', 'batt_full', null,'disabled', 'width75btn')}} - {{/if}} - {{:value.total_load}} - {{empty}} -
No APCs detected in connected powernet. - {{/for}} -
- {{/if}} -{{else}} -
- {{:helper.link('Scan For Sensors', 'refresh', { 'refresh' : 1})}} No active sensor. Printing sensor list. -

- {{for data.all_sensors}} - {{if value.alarm}} -
{{:helper.link(value.name, 'alert', { 'setsensor' : value.name})}} - {{else}} -
{{:helper.link(value.name, '' , { 'setsensor' : value.name})}} - {{/if}} - {{empty}} - WARN: No Sensors Detected! - {{/for}} -
-{{/if}} \ No newline at end of file diff --git a/nano/templates/power_monitor_map_content.tmpl b/nano/templates/power_monitor_map_content.tmpl deleted file mode 100644 index 291903144d..0000000000 --- a/nano/templates/power_monitor_map_content.tmpl +++ /dev/null @@ -1,33 +0,0 @@ - -{{if data.focus}} - {{for data.focus.apc_data}} - {{if value.z == config.mapZLevel}} -
- -
- {{/if}} - {{/for}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/power_monitor_map_header.tmpl b/nano/templates/power_monitor_map_header.tmpl deleted file mode 100644 index 171fd03429..0000000000 --- a/nano/templates/power_monitor_map_header.tmpl +++ /dev/null @@ -1,33 +0,0 @@ - -{{:helper.link('Show Network Information', 'script', {'showMap' : 0})}} -{{if data.focus}}Sensor selected: {{:data.focus.name}}{{/if}} -{{if data.map_levels.length > 1}} -
- Z Level:  - {{for data.map_levels }} - {{:helper.link(value, null, {'mapZLevel' : value}, null, config.mapZLevel == value ? 'selected' : null)}} - {{/for}} -
-{{/if}} -
- Zoom Level:  - - - - -
-
-
Sensors:
-
-{{for data.all_sensors}} - {{if value.alarm}} - {{:helper.link(value.name, 'alert', { 'setsensor' : value.name})}} - {{else}} - {{:helper.link(value.name, '' , { 'setsensor' : value.name})}} - {{/if}} -{{empty}} - WARN: No Sensors Detected! -{{/for}} diff --git a/nano/templates/pressure_regulator.tmpl b/nano/templates/pressure_regulator.tmpl deleted file mode 100644 index bbbfcc22df..0000000000 --- a/nano/templates/pressure_regulator.tmpl +++ /dev/null @@ -1,76 +0,0 @@ -
-
- Input Pressure: -
-
- {{:(data.input_pressure/100)}} kPa -
-
- -
-
- Output Pressure: -
-
- {{:(data.output_pressure/100)}} kPa -
-
- -
-
- Flow Rate: -
-
-
- {{:(data.last_flow_rate/10)}} L/s -
-
-
- -
- -
-
- Valve: -
-
- {{:helper.link(data.on? 'Unlocked' : 'Closed', null, {'toggle_valve' : 1})}} -
-
- -
-
- Pressure Regulation: -
-
- {{:helper.link('Off', null, {'regulate_mode' : 'off'}, data.regulate_mode == 0? 'selected' : null)}} - {{:helper.link('Input', null, {'regulate_mode' : 'input'}, data.regulate_mode == 1? 'selected' : null)}} - {{:helper.link('Output', null, {'regulate_mode' : 'output'}, data.regulate_mode == 2? 'selected' : null)}} -
-
- -
-
- Target Pressure: -
-
-
- {{:helper.link('MAX', null, {'set_press' : 'max'}, null)}} - {{:helper.link('SET', null, {'set_press' : 'set'}, null)}} -
 {{:(data.pressure_set/100)}} kPa 
-
-
-
- -
-
- Flow Rate Limit: -
-
-
- {{:helper.link('MAX', null, {'set_flow_rate' : 'max'}, null)}} - {{:helper.link('SET', null, {'set_flow_rate' : 'set'}, null)}} -
 {{:(data.set_flow_rate/10)}} L/s 
-
-
-
\ No newline at end of file diff --git a/nano/templates/radio_basic.tmpl b/nano/templates/radio_basic.tmpl deleted file mode 100644 index 6cfbb6dc7a..0000000000 --- a/nano/templates/radio_basic.tmpl +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - -{{if data.useSyndMode}} - {{:helper.syndicateMode()}} -{{/if}} - -
-
- Microphone -
-
- {{if data.mic_cut}} - {{:helper.link('On', null, null, 'disabled')}} - {{:helper.link('Off', null, null, 'disabled')}} - {{else}} - {{:helper.link('On', null, {'talk' : 0}, data.mic_status ? 'selected' : null)}} - {{:helper.link('Off', null, {'talk' : 1}, data.mic_status ? null : 'selected')}} - {{/if}} -
-
- -
-
- Speaker -
-
- {{if data.spk_cut}} - {{:helper.link('On', null, null, 'disabled')}} - {{:helper.link('Off', null, null, 'disabled')}} - {{else}} - {{:helper.link('On', null, {'listen' : 0}, data.speaker ? 'selected' : null)}} - {{:helper.link('Off', null, {'listen' : 1}, data.speaker ? null : 'selected')}} - {{/if}} -
-
- -{{if data.has_subspace}} -
-
- Subspace Transmission: -
-
- {{:helper.link('On', null, {'mode' : 1}, data.subspace ? 'selected' : null)}} - {{:helper.link('Off', null, {'mode' : 0}, data.subspace ? null : 'selected')}} -
-
-{{/if}} - -{{if data.has_loudspeaker}} -
-
- Loudspeaker: -
-
- {{:helper.link('On', null, {'shutup' : 0}, data.loudspeaker ? 'selected' : null)}} - {{:helper.link('Off', null, {'shutup' : 1}, data.loudspeaker ? null : 'selected')}} -
-
-{{/if}} - -
-
- Frequency: {{:data.freq}} -
-
- {{:helper.link('--', null, {'freq' : -10})}} - {{:helper.link('-', null, {'freq' : -2})}} - {{:helper.link('+', null, {'freq' : 2})}} - {{:helper.link('++', null, {'freq' : 10})}} -
-
- -{{if data.chan_list_len >= 1}} -

Channels

-
- {{for data.chan_list}} -
- {{:value.display_name}} -
-
- {{if value.secure_channel}} - {{:helper.link('On', null, {'ch_name' : value.chan, 'listen' : value.sec_channel_listen}, value.sec_channel_listen ? null : 'selected')}} - {{:helper.link('Off', null, {'ch_name' : value.chan, 'listen' : value.sec_channel_listen}, value.sec_channel_listen ? 'selected' : null)}} - {{else}} - {{:helper.link('Switch', null, {'spec_freq' : value.chan}, data.rawfreq == value.chan ? 'selected' : null)}} - {{/if}} -
- {{/for}} -{{/if}} diff --git a/nano/templates/rcon.tmpl b/nano/templates/rcon.tmpl deleted file mode 100644 index e16062aec4..0000000000 --- a/nano/templates/rcon.tmpl +++ /dev/null @@ -1,73 +0,0 @@ - -
{{:helper.link('Show/Hide SMES readings', 'folder', { 'hide_smes' : 1})}} -
{{:helper.link('Show/Hide SMES controls', 'folder', { 'hide_smes_details' : 1})}} -
{{:helper.link('Show/Hide Breaker readings', 'folder', { 'hide_breakers' : 1})}} -
-{{if data.hide_smes}} - SMES readings hidden.
-{{else}} - Detected SMES units with RCON support:
- {{for data.smes_info}} -
-
- {{:value.RCON_tag}} -
-
- -
- {{if value.charge > 50}} - {{:helper.displayBar(value.charge, 0, 100, 'good')}} - {{else value.charge > 25}} - {{:helper.displayBar(value.charge, 0, 100, 'average')}} - {{else}} - {{:helper.displayBar(value.charge, 0, 100, 'bad')}} - {{/if}} -
- {{:value.charge}}%
-
- {{if !data.hide_smes_details}} -
- Input: {{:value.input_val}} kW - {{:value.input_set ? "AUTO" : "OFF"}} - - {{:helper.link('', 'power', { 'smes_in_toggle' : value.RCON_tag})}} - {{:helper.link('', 'pencil', { 'smes_in_set' : value.RCON_tag})}} -
- Output: {{:value.output_val}} kW - {{:value.output_set ? "ONLINE" : "OFFLINE"}} - - {{:helper.link('', 'power', { 'smes_out_toggle' : value.RCON_tag})}} - {{:helper.link('', 'pencil', { 'smes_out_set' : value.RCON_tag})}} - -
- Output Load: - - {{:value.output_load}} kW - {{/if}} -
-
-
- {{empty}} - No connected SMES units detected!
- {{/for}} -{{/if}} -{{if data.hide_breakers}} - Breaker readings hidden.
-{{else}} - Detected Breaker Boxes with RCON support:
- {{for data.breaker_info}} -
-
- {{:value.RCON_tag}} -
-
- -
- {{:value.enabled ? "[ENABLED]" : "[DISABLED]"}} - - {{:helper.link('', 'power', {'toggle_breaker' : value.RCON_tag})}} -
-
-
- {{empty}} - No connected Breaker Boxes detected! - {{/for}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/sec_camera.tmpl b/nano/templates/sec_camera.tmpl deleted file mode 100644 index 21ecea71e7..0000000000 --- a/nano/templates/sec_camera.tmpl +++ /dev/null @@ -1,37 +0,0 @@ - -{{if data.map_levels.length}} - {{:helper.link('Show Map', 'pin-s', {'showMap' : 1})}} -{{/if}} -{{:helper.link('Reset', 'refresh', {'reset' : 1})}} -
-
-
Current Camera: 
-
- {{if data.current_camera}} -
{{:data.current_camera.name}}
- {{else}} -
None
- {{/if}} -
-
-
-
Networks:
-
-{{for data.networks}} - {{:helper.link(value, '', {'switch_network' : value}, null, data.current_network == value ? 'selected' : null)}} -{{/for}} -
-
Cameras:
-
-{{for data.cameras}} - {{if data.current_camera && value.name == data.current_camera.name}} - {{:helper.link(value.name, '', {'switch_camera' : value.camera}, 'selected')}} - {{else value.deact}} - {{:helper.link(value.name + " (deactivated)", '', {}, 'inactive')}} - {{else}} - {{:helper.link(value.name, '', {'switch_camera' : value.camera})}} - {{/if}} -{{/for}} diff --git a/nano/templates/sec_camera_map_content.tmpl b/nano/templates/sec_camera_map_content.tmpl deleted file mode 100644 index e9369c4b01..0000000000 --- a/nano/templates/sec_camera_map_content.tmpl +++ /dev/null @@ -1,20 +0,0 @@ - -{{for data.cameras}} - {{if value.z == config.mapZLevel}} -
- {{if data.current && value.name == data.current.name}} - {{:helper.link("#", '', {'switch_camera' : value.camera}, 'selected')}} - {{else value.deact}} - {{:helper.link('#', '', {}, 'inactive')}} - {{else}} - {{:helper.link("#", '', {'switch_camera' : value.camera})}} - {{/if}} - -
- {{/if}} -{{/for}} diff --git a/nano/templates/sec_camera_map_header.tmpl b/nano/templates/sec_camera_map_header.tmpl deleted file mode 100644 index 0281c70cf5..0000000000 --- a/nano/templates/sec_camera_map_header.tmpl +++ /dev/null @@ -1,38 +0,0 @@ - -{{:helper.link('Show Camera List', 'script', {'showMap' : 0})}} -{{:helper.link('Reset', 'refresh', {'reset' : 1})}} -
-
-
Current Camera: 
- {{if data.current_camera}} -
{{:data.current_camera.name}}
- {{else}} -
None
- {{/if}} -
-
-{{if data.map_levels.length > 1}} -
- Z Level:  - {{for data.map_levels }} - {{:helper.link(value, null, {'mapZLevel' : value}, null, config.mapZLevel == value ? 'selected' : null)}} - {{/for}} -
-{{/if}} -
- Zoom Level:  - - - - -
-
-
-
Networks:
-
-{{for data.networks}} - {{:helper.link(value, '', {'switch_network' : value}, null, data.current_network == value ? 'selected' : null)}} -{{/for}} \ No newline at end of file diff --git a/nano/templates/shutoff_monitor.tmpl b/nano/templates/shutoff_monitor.tmpl deleted file mode 100644 index 2597a1b6f5..0000000000 --- a/nano/templates/shutoff_monitor.tmpl +++ /dev/null @@ -1,13 +0,0 @@ -

Automated Shutoff Valve Monitoring Console

-
- -
NamePositionOpenModeActions -{{for data.valves}} -
{{:value.name}} - {{:value.x}}, {{:value.y}}, {{:value.z}} - {{:value.open ? 'Yes' : 'No'}} - {{:value.enabled ? 'Auto' : 'Manual'}} - {{:helper.link(value.open ? 'Close' : 'Open', null, {'toggle_open' : value.ref}, value.enabled ? 'disabled' : null)}} - {{:helper.link(value.enabled ? 'Manual' : 'Auto', null, {'toggle_enable' : value.ref})}} -{{/for}} -
\ No newline at end of file diff --git a/nano/templates/simple_airlock_console.tmpl b/nano/templates/simple_airlock_console.tmpl deleted file mode 100644 index ca49b20f6a..0000000000 --- a/nano/templates/simple_airlock_console.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -
-
-
- Chamber Pressure: -
-
- {{:helper.displayBar(data.chamber_pressure, 0, 200, (data.chamber_pressure < 80) || (data.chamber_pressure > 120) ? 'bad' : (data.chamber_pressure < 95) || (data.chamber_pressure > 110) ? 'average' : 'good')}} -
- {{:data.chamber_pressure}} kPa -
-
-
-
-
-
-
- {{:helper.link('Cycle to Exterior', 'arrowthickstop-1-w', {'command' : 'cycle_ext'}, data.processing ? 'disabled' : null)}} - {{:helper.link('Cycle to Interior', 'arrowthickstop-1-e', {'command' : 'cycle_int'}, data.processing ? 'disabled' : null)}} -
-
- {{if data.interior_status.state == "open"}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, 'redButton')}} - {{else}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, data.processing ? 'yellowButton' : null)}} - {{/if}} - {{if data.exterior_status.state == "open"}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, 'redButton')}} - {{else}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, data.processing ? 'yellowButton' : null)}} - {{/if}} -
-
-
- {{:helper.link('Abort', 'cancel', {'command' : 'abort'}, data.processing ? null : 'disabled', data.processing ? 'redButton' : null)}} -
-
\ No newline at end of file diff --git a/nano/templates/simple_docking_console.tmpl b/nano/templates/simple_docking_console.tmpl deleted file mode 100644 index 73c8ff8e3e..0000000000 --- a/nano/templates/simple_docking_console.tmpl +++ /dev/null @@ -1,99 +0,0 @@ -
-
-
- Docking Port Status: -
-
- {{if data.docking_status == "docked"}} - {{if !data.override_enabled}} - DOCKED - {{else}} - DOCKED-OVERRIDE ENABLED - {{/if}} - {{else data.docking_status == "docking"}} - {{if !data.override_enabled}} - DOCKING - {{else}} - DOCKING-OVERRIDE ENABLED - {{/if}} - {{else data.docking_status == "undocking"}} - {{if !data.override_enabled}} - UNDOCKING - {{else}} - UNDOCKING-OVERRIDE ENABLED - {{/if}} - {{else data.docking_status == "undocked"}} - {{if !data.override_enabled}} - NOT IN USE - {{else}} - OVERRIDE ENABLED - {{/if}} - {{else}} - ERROR - {{/if}} -
-
-
-
-
-
- Docking Hatch: -
-
- {{if data.docking_status == "docked"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed"}} - CLOSED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "docking"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "undocking"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "undocked"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else}} - ERROR - {{/if}} -
-
-
-
-
-
- {{if data.docking_status == "docked"}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - {{else}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', data.override_enabled ? 'redButton' : null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : 'yellowButton')}} - {{/if}} -
-
-
\ No newline at end of file diff --git a/nano/templates/simple_docking_console_pod.tmpl b/nano/templates/simple_docking_console_pod.tmpl deleted file mode 100644 index 07f055ea2c..0000000000 --- a/nano/templates/simple_docking_console_pod.tmpl +++ /dev/null @@ -1,101 +0,0 @@ -
-
-
- Docking Port Status: -
-
- {{if data.docking_status == "docked"}} - {{if !data.override_enabled}} - DOCKED - {{else}} - DOCKED-OVERRIDE ENABLED - {{/if}} - {{else data.docking_status == "docking"}} - {{if !data.override_enabled}} - DOCKING - {{else}} - DOCKING-OVERRIDE ENABLED - {{/if}} - {{else data.docking_status == "undocking"}} - {{if !data.override_enabled}} - UNDOCKING - {{else}} - UNDOCKING-OVERRIDE ENABLED - {{/if}} - {{else data.docking_status == "undocked"}} - {{if !data.override_enabled}} - NOT IN USE - {{else}} - OVERRIDE ENABLED - {{/if}} - {{else}} - ERROR - {{/if}} -
-
-
-
-
-
- Docking Hatch: -
-
- {{if data.docking_status == "docked"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed"}} - CLOSED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "docking"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "undocking"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else data.docking_status == "undocked"}} - {{if data.door_state == "open"}} - OPEN - {{else data.door_state == "closed" && data.door_lock == "locked"}} - SECURED - {{else data.door_state == "closed" && data.door_lock == "unlocked"}} - UNSECURED - {{else}} - ERROR - {{/if}} - {{else}} - ERROR - {{/if}} -
-
-
-
-
-
- {{if data.docking_status == "docked"}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}} - {{:helper.link('MANUAL EJECT', 'alert', {'command' : 'toggle_override'}, 'disabled', null)}} - {{else}} - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', data.override_enabled ? 'redButton' : null)}} - {{:helper.link('Override', 'alert', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : 'yellowButton')}} - {{:helper.link('MANUAL EJECT', 'alert', {'command' : 'toggle_override'}, data.can_force ? null : 'disabled', data.can_force ? 'redButton' : null)}} - {{/if}} -
-
-
\ No newline at end of file diff --git a/nano/templates/smartfridge.tmpl b/nano/templates/smartfridge.tmpl deleted file mode 100644 index cc25d760ce..0000000000 --- a/nano/templates/smartfridge.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -
- {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}} -
- -
-

Storage

- {{if data.secure}} - - {{:data.locked == -1 ? "Sec.re ACC_** //):securi_nt.diag=>##'or 1=1'%($..." : "Secure Access: Please have your identification ready."}} - - {{/if}} -
-
- {{if data.contents}} - {{for data.contents}} -
- {{:value.display_name}} ({{:value.quantity}} available) -
Vend: 
{{:helper.link('x1', 'circle-arrow-s', { "vend" : value.vend, "amount" : 1 }, null, 'statusValue')}} - {{if value.quantity >= 5}} - {{:helper.link('x5', 'circle-arrow-s', { "vend" : value.vend, "amount" : 5 }, null, 'statusValue')}} - {{/if}} - {{if value.quantity >= 10}} - {{:helper.link('x10', 'circle-arrow-s', { "vend" : value.vend, "amount" : 10 }, null, 'statusValue')}} - {{/if}} - {{if value.quantity >= 25}} - {{:helper.link('x25', 'circle-arrow-s', { "vend" : value.vend, "amount" : 25 }, null, 'statusValue')}} - {{/if}} - {{if value.quantity > 1}} - {{:helper.link('All', 'circle-arrow-s', { "vend" : value.vend, "amount" : value.quantity }, null, 'statusValue')}} - {{/if}} -
- {{/for}} - {{else}} - No products loaded. - {{/if}} -
diff --git a/nano/templates/smes.tmpl b/nano/templates/smes.tmpl deleted file mode 100644 index bdbff2da0e..0000000000 --- a/nano/templates/smes.tmpl +++ /dev/null @@ -1,104 +0,0 @@ -
-
- Stored Charge: -
-
- {{:helper.displayBar(data.storedCapacity, 0, 100, data.charging ? 'good' : 'average')}} -
- {{:helper.round(data.storedCapacity)}}% -

-
- {{:data.storedCapacityAbs}} kWh / {{:data.storedCapacityMax}} kWh -
-
-
- -

Input Management

-
-
- Charge Mode: -
-
- {{:helper.link('Auto', 'refresh', {'cmode' : 1}, data.chargeMode ? 'selected' : null)}}{{:helper.link('Off', 'close', {'cmode' : 1}, data.chargeMode ? null : 'selected')}} -   - {{if data.charging == 2}} - [Charging] - {{else data.charging == 1}} - [Partially Charging] - {{else}} - [Not Charging] - {{/if}} -
-
- -
-
- Input Level: -
-
- {{:helper.displayBar(data.chargeLevel, 0, data.chargeMax)}} -
- {{:helper.link('MIN', null, {'input' : 'min'}, (data.chargeLevel > 0) ? null : 'disabled')}} - {{:helper.link('SET', null, {'input' : 'set'}, null)}} - {{:helper.link('MAX', null, {'input' : 'max'}, (data.chargeLevel < data.chargeMax) ? null : 'disabled')}} -
 {{:data.chargeLevel}} kW 
-
-
-
- -
-
- Input Load: -
-
- {{:helper.displayBar(data.chargeLoad, 0, data.chargeMax, (data.chargeLoad < data.chargeLevel) ? 'good' : 'average')}} -
- {{:data.chargeLoad}} kW -
-
-
- -

Output Management

-
-
- Output Status: -
-
- {{:helper.link('Online', 'power', {'online' : 1}, data.outputOnline ? 'selected' : null)}}{{:helper.link('Offline', 'close', {'online' : 1}, data.outputOnline ? null : 'selected')}} -   - {{if data.outputting == 2}} - [Outputting] - {{else data.outputting == 1}} - [Stored energy too low] - {{else}} - [Not Outputting] - {{/if}} -
-
- -
-
- Output Level: -
-
- {{:helper.displayBar(data.outputLevel, 0, data.outputMax)}} -
- {{:helper.link('MIN', null, {'output' : 'min'}, (data.outputLevel > 0) ? null : 'disabled')}} - {{:helper.link('SET', null, {'output' : 'set'}, null)}} - {{:helper.link('MAX', null, {'output' : 'max'}, (data.outputLevel < data.outputMax) ? null : 'disabled')}} -
 {{:data.outputLevel}} kW 
-
-
-
- -
-
- Output Load: -
-
- {{:helper.displayBar(data.outputLoad, 0, data.outputMax, (data.outputLoad < data.outputLevel) ? 'good' : 'average')}} -
- {{:data.outputLoad}} kW -
-
-
\ No newline at end of file diff --git a/nano/templates/supermatter_crystal.tmpl b/nano/templates/supermatter_crystal.tmpl deleted file mode 100644 index b06aaae746..0000000000 --- a/nano/templates/supermatter_crystal.tmpl +++ /dev/null @@ -1,25 +0,0 @@ -{{if data.detonating}} -
-

CRYSTAL DELAMINATING

-

Evacuate area immediately

-
-
-{{else}} -

Crystal Integrity

- {{:helper.displayBar(data.integrity_percentage, 0, 100, (data.integrity_percentage >= 90) ? 'good' : (data.integrity_percentage >= 25) ? 'average' : 'bad')}} - {{:data.integrity_percentage}} % -

Environment

- - Temperature: - - - {{:helper.displayBar(data.ambient_temp, 0, 10000, (data.ambient_temp >= 5000) ? 'bad' : (data.ambient_temp >= 4000) ? 'average' : 'good')}} - {{:data.ambient_temp}} K - - - Pressure: - - - {{:data.ambient_pressure}} kPa - -{{/if}} \ No newline at end of file diff --git a/nano/templates/supermatter_monitor.tmpl b/nano/templates/supermatter_monitor.tmpl deleted file mode 100644 index 1d7bdb7cff..0000000000 --- a/nano/templates/supermatter_monitor.tmpl +++ /dev/null @@ -1,125 +0,0 @@ -{{if data.active}} - {{:helper.link('Back to Menu', null, {'clear' : 1})}}
-
-
- Core Integrity: -
-
- {{:helper.displayBar(data.SM_integrity, 0, 100, (data.SM_integrity == 100) ? 'good' : (data.SM_integrity >= 50) ? 'average' : 'bad')}} {{:data.SM_integrity}}% -
-
- Relative EER: -
-
- {{if data.SM_power > 300}} - {{:data.SM_power}} MeV/cm3 - {{else data.SM_power > 150}} - {{:data.SM_power}} MeV/cm3 - {{else}} - {{:data.SM_power}} MeV/cm3 - {{/if}} -
-
- Temperature: -
-
- {{if data.SM_ambienttemp > 5000}} - {{:data.SM_ambienttemp}} K - {{else data.SM_ambienttemp > 4000}} - {{:data.SM_ambienttemp}} K - {{else}} - {{:data.SM_ambienttemp}} K - {{/if}} -
-
- Pressure: -
-
- {{if data.SM_ambientpressure > 10000}} - {{:data.SM_ambientpressure}} kPa - {{else data.SM_ambientpressure > 5000}} - {{:data.SM_ambientpressure}} kPa - {{else}} - {{:data.SM_ambientpressure}} kPa - {{/if}} -
-
- Chamber EPR: -
-
- {{if data.SM_EPR > 4}} - {{:data.SM_EPR}} - {{else data.SM_EPR > 2.5}} - {{:data.SM_EPR}} - {{else data.SM_EPR < 1}} - {{:data.SM_EPR}} - {{else}} - {{:data.SM_EPR}} - {{/if}} -
-
-

-
- Gas Composition: -
-
-
-
- O2: -
-
- {{:data.SM_gas_O2}} % -
-
- CO2: -
-
- {{:data.SM_gas_CO2}} % -
-
- N2: -
-
- {{:data.SM_gas_N2}} % -
-
- PH: -
-
- {{:data.SM_gas_PH}} % -
-
- N2O: -
-
- {{:data.SM_gas_N2O}} % -
-
-
- -{{else}} - {{:helper.link('Refresh', null, {'refresh' : 1})}}
- {{for data.supermatters}} -
-
- Area: -
-
- {{:value.area_name}} - (#{{:value.uid}}) -
-
- Integrity: -
-
- {{:value.integrity}} % -
-
- Options: -
-
- {{:helper.link('View Details', null, {'set' : value.uid})}} -
-
- {{/for}} -{{/if}} diff --git a/nano/templates/tanks.tmpl b/nano/templates/tanks.tmpl deleted file mode 100644 index c9d4e6c335..0000000000 --- a/nano/templates/tanks.tmpl +++ /dev/null @@ -1,47 +0,0 @@ -{{if data.maskConnected}} -
This tank is connected to a mask.
-{{else}} -
This tank is NOT connected to a mask.
-{{/if}} - -
-
- Tank Pressure: -
-
- {{:helper.displayBar(data.tankPressure, 0, 1013, (data.tankPressure > 200) ? 'good' : ((data.tankPressure > 100) ? 'average' : 'bad'))}} -
- {{:data.tankPressure}} kPa -
-
-
- -
 
- -
-
- Mask Release Pressure: -
-
- {{:helper.displayBar(data.releasePressure, 0, data.maxReleasePressure, (data.releasePressure >= 23) ? null : ((data.releasePressure >= 17) ? 'average' : 'bad'))}} -
- {{:helper.link('-', null, {'dist_p' : -10}, (data.releasePressure > 0) ? null : 'disabled')}} - {{:helper.link('-', null, {'dist_p' : -1}, (data.releasePressure > 0) ? null : 'disabled')}} -
 {{:data.releasePressure}} kPa 
- {{:helper.link('+', null, {'dist_p' : 1}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'dist_p' : 10}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('Max', null, {'dist_p' : 'max'}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('Reset', null, {'dist_p' : 'reset'}, (data.releasePressure != data.defaultReleasePressure) ? null : 'disabled')}} -
-
-
- -
-
- Mask Release Valve: -
-
- {{:helper.link('Open', 'unlocked', {'stat' : 1}, (!data.maskConnected) ? 'disabled' : (data.valveOpen ? 'selected' : null))}}{{:helper.link('Close', 'locked', {'stat' : 1}, data.valveOpen ? null : 'selected')}} -
-
- diff --git a/nano/templates/vending_machine.tmpl b/nano/templates/vending_machine.tmpl deleted file mode 100644 index 93d5c1007c..0000000000 --- a/nano/templates/vending_machine.tmpl +++ /dev/null @@ -1,56 +0,0 @@ - - -{{if data.mode == 0}} -

Items available

-
- {{for data.products}} -
-
- {{if value.price > 0}} - {{:helper.link('Buy (' + value.price + ')', 'cart', { "vend" : value.key }, value.amount > 0 ? null : 'disabled')}} - {{else}} - {{:helper.link('Vend', 'circle-arrow-s', { "vend" : value.key }, value.amount > 0 ? null : 'disabled')}} - {{/if}} -
-
- {{if value.color}}{{:value.name}} - {{else}}{{:value.name}} - {{/if}} - ({{:value.amount ? value.amount : "NONE LEFT"}}) -
-
- {{empty}} - No items available! - {{/for}} -
-{{if data.coin}} -

Coin

-
-
Coin deposited:
-
{{:helper.link(data.coin, 'eject', {'remove_coin' : 1})}}
-
-{{/if}} -{{else data.mode == 1}} -

Item selected

-
-
-
Item selected:
{{:data.product}}
-
Charge:
{{:data.price}}
-
-
- {{if data.message_err}} {{/if}} {{:data.message}} -
-
- {{:helper.link('Cancel', 'arrowreturn-1-w', {'cancelpurchase' : 1})}} -
-
-{{/if}} -{{if data.panel}} -

Maintenance panel

-
-
Speaker
{{:helper.link(data.speaker ? 'Enabled' : 'Disabled', 'gear', {'togglevoice' : 1})}}
-
-{{/if}} \ No newline at end of file diff --git a/sound/machines/rig/rigdown.ogg b/sound/machines/rig/rigdown.ogg new file mode 100644 index 0000000000..2120757332 Binary files /dev/null and b/sound/machines/rig/rigdown.ogg differ diff --git a/sound/machines/rig/rigerror.ogg b/sound/machines/rig/rigerror.ogg new file mode 100644 index 0000000000..909d6a19e2 Binary files /dev/null and b/sound/machines/rig/rigerror.ogg differ diff --git a/sound/machines/rig/rigonline.ogg b/sound/machines/rig/rigonline.ogg new file mode 100644 index 0000000000..dae104f965 Binary files /dev/null and b/sound/machines/rig/rigonline.ogg differ diff --git a/sound/machines/rig/rigstarted.ogg b/sound/machines/rig/rigstarted.ogg new file mode 100644 index 0000000000..d7bb9716f4 Binary files /dev/null and b/sound/machines/rig/rigstarted.ogg differ diff --git a/sound/machines/rig/rigstep.ogg b/sound/machines/rig/rigstep.ogg new file mode 100644 index 0000000000..02d3eff512 Binary files /dev/null and b/sound/machines/rig/rigstep.ogg differ diff --git a/sound/machines/shower/shower_end.ogg b/sound/machines/shower/shower_end.ogg index 80b93af39e..4ab4479a06 100644 Binary files a/sound/machines/shower/shower_end.ogg and b/sound/machines/shower/shower_end.ogg differ diff --git a/sound/machines/shower/shower_mid1.ogg b/sound/machines/shower/shower_mid1.ogg index e1ae5a0c45..3e35ac57af 100644 Binary files a/sound/machines/shower/shower_mid1.ogg and b/sound/machines/shower/shower_mid1.ogg differ diff --git a/sound/machines/shower/shower_mid2.ogg b/sound/machines/shower/shower_mid2.ogg index 4a54acd352..66da790cb1 100644 Binary files a/sound/machines/shower/shower_mid2.ogg and b/sound/machines/shower/shower_mid2.ogg differ diff --git a/sound/machines/shower/shower_mid3.ogg b/sound/machines/shower/shower_mid3.ogg index 8b4776a9b9..0c03ce6e43 100644 Binary files a/sound/machines/shower/shower_mid3.ogg and b/sound/machines/shower/shower_mid3.ogg differ diff --git a/sound/machines/shower/shower_start.ogg b/sound/machines/shower/shower_start.ogg index e5529f401b..9fb6aa22aa 100644 Binary files a/sound/machines/shower/shower_start.ogg and b/sound/machines/shower/shower_start.ogg differ diff --git a/tgui/packages/common/string.js b/tgui/packages/common/string.js index 1a06c67ecf..a3da0885a1 100644 --- a/tgui/packages/common/string.js +++ b/tgui/packages/common/string.js @@ -120,7 +120,7 @@ export const decodeHtmlEntities = str => { if (!str) { return str; } - const translate_re = /&(nbsp|amp|quot|lt|gt|apos);/g; + const translate_re = /&(nbsp|amp|quot|lt|gt|apos|trade);/g; const translate = { nbsp: ' ', amp: '&', @@ -128,6 +128,7 @@ export const decodeHtmlEntities = str => { lt: '<', gt: '>', apos: '\'', + trade: 'â„¢', }; return str // Newline tags diff --git a/tgui/packages/tgui/format.js b/tgui/packages/tgui/format.js index 1f8420860e..db21025bdf 100644 --- a/tgui/packages/tgui/format.js +++ b/tgui/packages/tgui/format.js @@ -94,3 +94,13 @@ export const formatMoney = (value, precision = 0) => { } return result; }; + +export const formatCommaNumber = value => { + if (!Number.isFinite(value)) { + return value; + } + // From http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript + let parts = value.toString().split("."); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); + return parts.join("."); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/AICard.js b/tgui/packages/tgui/interfaces/AICard.js new file mode 100644 index 0000000000..68ecd1af16 --- /dev/null +++ b/tgui/packages/tgui/interfaces/AICard.js @@ -0,0 +1,122 @@ +import { useBackend } from "../backend"; +import { Button, ProgressBar, LabeledList, Box, Section } from "../components"; +import { Window } from "../layouts"; + +export const AICard = (props, context) => { + const { act, data } = useBackend(context); + + const { + has_ai, + integrity, + backup_capacitor, + flushing, + has_laws, + laws, + wireless, + radio, + } = data; + + if (has_ai === 0) { + return ( + + +
+ +

No AI detected.

+
+
+
+
+ ); + } else { + + let integrityColor = null; // Handles changing color of the integrity bar + if (integrity >= 75) { integrityColor = 'green'; } + else if (integrity >= 25) { integrityColor = 'yellow'; } + else { integrityColor = 'red'; } + + let powerColor = null; + if (backup_capacitor >= 75) { powerColor = 'green'; } + if (backup_capacitor >= 25) { powerColor = 'yellow'; } + else { powerColor = 'red'; } + + return ( + + +
+ +

{name}

+
+ + + + + + + + + + + +

{flushing === 1 ? "Wipe of AI in progress..." : ""}

+
+
+ +
+ {!!has_laws && ( + + {laws.map((value, key) => ( + + {value} + + ))} + + ) || ( // Else, no laws. + +

No laws detected.

+
+ )} +
+ +
+ + +
+
+
+ ); + } +}; diff --git a/tgui/packages/tgui/interfaces/APC.js b/tgui/packages/tgui/interfaces/APC.js new file mode 100644 index 0000000000..1ee7419b47 --- /dev/null +++ b/tgui/packages/tgui/interfaces/APC.js @@ -0,0 +1,288 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Box, Button, Dimmer, Icon, LabeledList, NoticeBox, ProgressBar, Section, Flex } from '../components'; +import { Window } from '../layouts'; +import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox'; +import { FullscreenNotice } from './common/FullscreenNotice'; + +export const APC = (props, context) => { + const { act, data } = useBackend(context); + + let body = ; + + if (data.gridCheck) { + body = ; + } else if (data.failTime) { + body = ; + } + + return ( + + + {body} + + + ); +}; + +const powerStatusMap = { + 2: { + color: 'good', + externalPowerText: 'External Power', + chargingText: 'Fully Charged', + }, + 1: { + color: 'average', + externalPowerText: 'Low External Power', + chargingText: 'Charging', + }, + 0: { + color: 'bad', + externalPowerText: 'No External Power', + chargingText: 'Not Charging', + }, +}; + +const malfMap = { + 1: { + icon: 'terminal', + content: 'Override Programming', + action: 'hack', + }, + // 2: { + // icon: 'caret-square-down', + // content: 'Shunt Core Process', + // action: 'occupy', + // }, + // 3: { + // icon: 'caret-square-left', + // content: 'Return to Main Core', + // action: 'deoccupy', + // }, + // 4: { + // icon: 'caret-square-down', + // content: 'Shunt Core Process', + // action: 'occupy', + // }, +}; + +const ApcContent = (props, context) => { + const { act, data } = useBackend(context); + const locked = data.locked && !data.siliconUser; + const normallyLocked = data.normallyLocked; + const externalPowerStatus = powerStatusMap[data.externalPower] + || powerStatusMap[0]; + const chargingStatus = powerStatusMap[data.chargingStatus] + || powerStatusMap[0]; + const channelArray = data.powerChannels || []; + // const malfStatus = malfMap[data.malfStatus] || null; + const adjustedCellChange = data.powerCellStatus / 100; + + return ( + + + Fault in ID authenticator. + Please contact maintenance for service. + + )} /> +
+ + act('breaker')} /> + )}> + [ {externalPowerStatus.externalPowerText} ] + + + + + act('charge')} /> + )}> + [ {chargingStatus.chargingText} ] + + +
+
+ + {channelArray.map(channel => { + const { topicParams } = channel; + return ( + + = 2 ? 'good' : 'bad'}> + {channel.status >= 2 ? 'On' : 'Off'} + +
+
act('overload')} /> + )}> + + act('cover')} /> + )} /> + +
+ + ); +}; + +const GridCheck = (props, context) => { + return ( + + + + + + Power surge detected, grid check in effect... + + + ); +}; + +const ApcFailure = (props, context) => { + const { data, act } = useBackend(context); + + let rebootOptions = ( +