diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index af8d5769804..33573573aee 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -18,6 +18,7 @@
/obj/machinery/power/apc
name = "area power controller"
+ desc = "A control terminal for the area electrical systems."
icon_state = "apc0"
anchored = 1
@@ -66,14 +67,6 @@
return
..()
-/obj/machinery/power/apc/connect_to_network()
- //Override because the APC does not directly connect to the network; it goes through a terminal.
- //The terminal is what the power computer looks for anyway.
- if(!terminal)
- make_terminal()
- if(terminal)
- terminal.connect_to_network()
-
/obj/machinery/power/apc/New(turf/loc, var/ndir, var/building=0)
..()
wires = new(src)
@@ -133,7 +126,7 @@
set src in oview(1)
if(usr /*&& !usr.stat*/)
- usr << "A control terminal for the area electrical systems."
+ ..()
if(stat & BROKEN)
usr << "Looks broken."
return
@@ -169,10 +162,7 @@
else
icon_state = basestate
else if (opened == 2)
- if ((stat & BROKEN) || malfhack )
- icon_state = "[basestate]-b-nocover"
- else /* if (emagged)*/
- icon_state = "[basestate]-nocover"
+ icon_state = "[basestate]-nocover"
else if (stat & BROKEN)
icon_state = "apc-b"
else if(emagged || malfai)
@@ -320,7 +310,7 @@
user << "You start adding cables to the APC frame..."
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
if(do_after(user, 20) && C.amount >= 10)
- var/turf/T = get_turf(src)
+ var/turf/T = get_turf_loc(src)
var/obj/structure/cable/N = T.get_cable_node()
if (prob(50) && electrocute_mob(usr, N, N))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
@@ -409,10 +399,14 @@
opened = 1
update_icon()
else
+ // The extra crowbar thing fixes MoMMIs not being able to remove APCs.
+ // They can just pop them off with a crowbar.
if ( ((stat & BROKEN) || malfhack) \
&& !opened \
- && W.force >= 5 \
- && W.w_class >= 3.0 \
+ && ( \
+ (W.force >= 5 && W.w_class >= 3.0) \
+ || istype(W,/obj/item/weapon/crowbar) \
+ ) \
&& prob(20) )
opened = 2
user.visible_message("\red The APC cover was knocked down with the [W.name] by [user.name]!", \
@@ -438,9 +432,12 @@
if(!user)
return
src.add_fingerprint(user)
- if(usr == user && opened && (!issilicon(user)))
+ if(usr == user && opened)
if(cell)
- user.put_in_hands(cell)
+ if(issilicon(user))
+ cell.loc=src.loc // Drop it, whoops.
+ else
+ user.put_in_hands(cell)
cell.add_fingerprint(user)
cell.updateicon()
@@ -452,6 +449,11 @@
return
if(stat & (BROKEN|MAINT))
return
+
+ if(ishuman(user))
+ if(istype(user:gloves, /obj/item/clothing/gloves/space_ninja)&&user:gloves:candrain&&!user:gloves:draining)
+ call(/obj/item/clothing/gloves/space_ninja/proc/drain)("APC",src,user:wear_suit)
+ return
// do APC interaction
user.set_machine(src)
src.interact(user)
@@ -485,134 +487,87 @@
if(wiresexposed /*&& (!istype(user, /mob/living/silicon))*/) //Commented out the typecheck to allow engiborgs to repair damaged apcs.
wires.Interact(user)
- user.set_machine(src)
- var/t = "" //"Area Power Controller ([area.name])"
-
- //This goes after the wire stuff. They should be able to fix a physical problem when a wire is cut
- if ( (get_dist(src, user) > 1 ))
- if (!issilicon(user))
- user.unset_machine()
- user << browse(null, "window=apc")
- return
- else if (issilicon(user) && src.aidisabled && !src.malfhack)
- user << "AI control for this APC interface has been disabled."
- user.unset_machine()
- user << browse(null, "window=apc")
- return
- else if (src.malfai && isAI(user))
- var/mob/living/silicon/ai/AI = user
- if ((src.malfai != AI && src.malfai != AI.parent) && !islinked(AI, malfai))
- user << "AI control for this APC interface has been disabled."
- user.unset_machine()
- user << browse(null, "window=apc")
- return
+ return ui_interact(user)
- if(locked && (!istype(user, /mob/living/silicon)))
- t += "
Swipe ID card to unlock interface
"
- t += "Status
"
- t += "Main Breaker: [operating ? "On" : "Off"]
"
- t += "External Power: [ main_status ? (main_status ==2 ? "Good" : "Low") : "None"]
"
- t += "Power Cell: [cell ? "[round(cell.percent())]%" : "Not connected."]"
- if(cell)
- t += "
Charge Mode: [chargemode ? "Auto" : "Off"]"
- t += " ([charging ? ( charging == 1 ? "Charging" : "Fully charged" ) : "Not charging"])"
-
- t += "Power Channels
"
-
- var/list/L = list ("Off","Off (Auto)", "On", "On (Auto)")
-
- t += "Equipment: [add_lspace(lastused_equip, 6)] W : [L[equipment+1]]
"
- t += "Lighting: [add_lspace(lastused_light, 6)] W : [L[lighting+1]]
"
- t += "Environmental:[add_lspace(lastused_environ, 6)] W : [L[environ+1]]
"
-
- t += "
Total Load: [lastused_light + lastused_equip + lastused_environ] W"
- t += "
Cover Lock: [coverlocked ? "Engaged" : "Disengaged"]"
-
- else
- if (!istype(user, /mob/living/silicon))
- t += "Swipe ID card to lock interface
"
- t += "Status
"
- t += "Main Breaker: [operating ? "On Off" : "On Off" ]
"
- t += "External power : [ main_status ? (main_status ==2 ? "Good" : "Low") : "None"]
"
- if(cell)
- t += "Power cell: [round(cell.percent())]%"
- t += "
Charge mode: [chargemode ? "Off Auto" : "Off Auto"]"
- t += " ([charging ? ( charging == 1 ? "Charging" : "Fully charged" ) : "Not charging"])"
+/obj/machinery/power/apc/proc/get_malf_status(mob/user)
+ if (ticker && ticker.mode && (user.mind in ticker.mode.malf_ai) && istype(user, /mob/living/silicon/ai))
+ if (src.malfai == (user:parent ? user:parent : user))
+ if (src.occupant == user)
+ return 3 // 3 = User is shunted in this APC
+ else if (istype(user.loc, /obj/machinery/power/apc))
+ return 4 // 4 = User is shunted in another APC
+ else
+ return 2 // 2 = APC hacked by user, and user is in its core.
else
- t += "Power cell: Not connected."
-
- t += "
Power channels
"
-
- t += "Equipment: [add_lspace(lastused_equip, 6)] W : "
- var/key = "eqp"
- switch(equipment)
- if(0)
- t += "Off On Auto"
- if(1)
- t += "Off On Auto (Off)"
- if(2)
- t += "Off On Auto"
- if(3)
- t += "Off On Auto (On)"
- t +="
"
-
- t += "Lighting: [add_lspace(lastused_light, 6)] W : "
- key = "lgt"
- switch(lighting)
- if(0)
- t += "Off On Auto"
- if(1)
- t += "Off On Auto (Off)"
- if(2)
- t += "Off On Auto"
- if(3)
- t += "Off On Auto (On)"
- t +="
"
+ return 1 // 1 = APC not hacked.
+ else
+ return 0 // 0 = User is not a Malf AI
- t += "Environmental:[add_lspace(lastused_environ, 6)] W : "
- key = "env"
- switch(environ)
- if(0)
- t += "Off On Auto"
- if(1)
- t += "Off On Auto (Off)"
- if(2)
- t += "Off On Auto"
- if(3)
- t += "Off On Auto (On)"
+/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main")
+ if(!user)
+ return
+ var/list/data = list(
+ "locked" = locked,
+ "isOperating" = operating,
+ "externalPower" = main_status,
+ "powerCellStatus" = cell ? cell.percent() : null,
+ "chargeMode" = chargemode,
+ "chargingStatus" = charging,
+ "totalLoad" = lastused_equip + lastused_light + lastused_environ,
+ "coverLocked" = coverlocked,
+ "siliconUser" = istype(user, /mob/living/silicon),
+ "malfStatus" = get_malf_status(user),
+ "powerChannels" = list(
+ list(
+ "title" = "Equipment",
+ "powerLoad" = lastused_equip,
+ "status" = equipment,
+ "topicParams" = list(
+ "auto" = list("eqp" = 3),
+ "on" = list("eqp" = 2),
+ "off" = list("eqp" = 1)
+ )
+ ),
+ list(
+ "title" = "Lighting",
+ "powerLoad" = lastused_light,
+ "status" = lighting,
+ "topicParams" = list(
+ "auto" = list("lgt" = 3),
+ "on" = list("lgt" = 2),
+ "off" = list("lgt" = 1)
+ )
+ ),
+ list(
+ "title" = "Environment",
+ "powerLoad" = lastused_environ,
+ "status" = environ,
+ "topicParams" = list(
+ "auto" = list("env" = 3),
+ "on" = list("env" = 2),
+ "off" = list("env" = 1)
+ )
+ )
+ )
+ )
- t += "
Total Load: [lastused_light + lastused_equip + lastused_environ] W
"
- t += "
Cover Lock: [coverlocked ? "Engaged" : "Disengaged"]"
-
-
- if (istype(user, /mob/living/silicon))
- t += "
Overload lighting circuit
"
- if (ticker && ticker.mode)
-// world << "there's a ticker"
- if(user.mind in ticker.mode.malf_ai)
-// world << "ticker says its malf"
- if (!src.malfai)
- t += "
Override Programming
"
- else
- t += "
APC Hacked
"
- if(!src.occupant)
- t += "Shunt Core Processes
"
- else
- t += "Core Processes Uploaded
"
-
- //t += "
Close"
-
- //user << browse(t, "window=apc")
- //onclose(user, "apc")
- var/datum/browser/popup = new(user, "apc", "[area.name] APC")
- popup.set_content(t)
- popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
- popup.open()
- return
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
+ if (!ui)
+ // the ui does not exist, so we'll create a new one
+ ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 500, data["siliconUser"] ? 465 : 390)
+ // When the UI is first opened this is the data it will use
+ ui.set_initial_data(data)
+ ui.open()
+ // Auto update every Master Controller tick
+ ui.set_auto_update(1)
+ else
+ // The UI is already open so push the new data to it
+ ui.push_data(data)
+ return
/obj/machinery/power/apc/proc/report()
return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
@@ -638,7 +593,7 @@
/obj/machinery/power/apc/proc/can_use(mob/user as mob, var/loud = 0) //used by attack_hand() and Topic()
- if (user.stat)
+ if (user.stat && !isobserver(user))
user << "\red You must be conscious to use this [src]!"
return 0
if(!user.client)
@@ -647,8 +602,6 @@
istype(user, /mob/living/silicon) || \
istype(user, /mob/living/carbon/monkey) /*&& ticker && ticker.mode.name == "monkey"*/) )
user << "\red You don't have the dexterity to use this [src]!"
- user << browse(null, "window=apc")
- user.unset_machine()
return 0
if(user.restrained())
user << "\red You must have free hands to use this [src]"
@@ -668,14 +621,12 @@
) \
)
if(!loud)
- user << "\red \The [src] have AI control disabled!"
+ user << "\red \The [src] has AI control disabled!"
user << browse(null, "window=apc")
user.unset_machine()
return 0
else
if ((!in_range(src, user) || !istype(src.loc, /turf)))
- user << browse(null, "window=apc")
- user.unset_machine()
return 0
var/mob/living/carbon/human/H = user
@@ -691,13 +642,10 @@
/obj/machinery/power/apc/Topic(href, href_list)
if(..())
- return
+ return 0
- if(!isrobot(usr))
- if(!can_use(usr, 1))
- return
-
- usr.set_machine(src)
+ if(!can_use(usr, 1))
+ return 0
if (href_list["lock"])
coverlocked = !coverlocked
@@ -713,44 +661,32 @@
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["close"] )
- usr << browse(null, "window=apc")
- usr.unset_machine()
- return
- else if (href_list["close2"])
- usr << browse(null, "window=apcwires")
- usr.unset_machine()
- return
-
else if (href_list["overload"])
- if( istype(usr, /mob/living/silicon) && !src.aidisabled )
+ if(istype(usr, /mob/living/silicon))
src.overload_lighting()
else if (href_list["malfhack"])
var/mob/living/silicon/ai/malfai = usr
- if( istype(malfai, /mob/living/silicon/ai) && !src.aidisabled )
+ if(get_malf_status(malfai)==1)
if (malfai.malfhacking)
malfai << "You are already hacking an APC."
- return
+ return 1
malfai << "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process."
malfai.malfhack = src
malfai.malfhacking = 1
@@ -759,6 +695,7 @@
if (!src.aidisabled)
malfai.malfhack = null
malfai.malfhacking = 0
+ locked = 1
if (ticker.mode.config_tag == "malfunction")
if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
ticker.mode:apcs++
@@ -770,14 +707,22 @@
update_icon()
else if (href_list["occupyapc"])
- malfoccupy(usr)
+ if(get_malf_status(usr))
+ malfoccupy(usr)
else if (href_list["deoccupyapc"])
- malfvacate()
+ if(get_malf_status(usr))
+ malfvacate()
- src.updateDialog()
+ else if (href_list["toggleaccess"])
+ if(istype(usr, /mob/living/silicon))
+ if(emagged || (stat & (BROKEN|MAINT)))
+ usr << "The APC does not respond to the command."
+ else
+ locked = !locked
+ update_icon()
- return
+ return 1
/obj/machinery/power/apc/proc/toggle_breaker()
operating = !operating
@@ -816,9 +761,9 @@
src.occupant.verbs += /mob/living/silicon/ai/proc/corereturn
src.occupant.verbs += /datum/game_mode/malfunction/proc/takeover
src.occupant.cancel_camera()
-
- for(var/obj/item/weapon/pinpointer/point in world)
- point.the_disk = src //the pinpointer will detect the shunted AI
+ if (seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
+ for(var/obj/item/weapon/pinpointer/point in world)
+ point.the_disk = src //the pinpointer will detect the shunted AI
/obj/machinery/power/apc/proc/malfvacate(var/forced)
@@ -829,6 +774,12 @@
src.occupant.parent.adjustOxyLoss(src.occupant.getOxyLoss())
src.occupant.parent.cancel_camera()
del(src.occupant)
+ if (seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
+ for(var/obj/item/weapon/pinpointer/point in world)
+ for(var/datum/mind/AI_mind in ticker.mode.malf_ai)
+ var/mob/living/silicon/ai/A = AI_mind.current // the current mob the mind owns
+ if(A.stat != DEAD)
+ point.the_disk = A //The pinpointer tracks the AI back into its core.
else
src.occupant << "\red Primary core damaged, unable to return core processes."
@@ -836,9 +787,8 @@
src.occupant.loc = src.loc
src.occupant.death()
src.occupant.gib()
-
- for(var/obj/item/weapon/pinpointer/point in world)
- point.the_disk = null //the pinpointer will go back to pointing at the nuke disc.
+ for(var/obj/item/weapon/pinpointer/point in world)
+ point.the_disk = null //the pinpointer will go back to pointing at the nuke disc.
/obj/machinery/power/apc/proc/ion_act()
@@ -928,8 +878,8 @@
if(cell && !shorted)
-
// draw power from cell as before
+
var/cellused = min(cell.charge, CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell
cell.use(cellused)
@@ -1042,9 +992,6 @@
else if (last_ch != charging)
queue_icon_update()
- //src.updateDialog()
- src.updateDialog()
-
// val 0=off, 1=off(auto) 2=on 3=on(auto)
// on 0=off, 1=on, 2=autooff
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index fad6db67dd8..47b056c7912 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -152,7 +152,7 @@
// 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, "chem_dispenser.tmpl", ui_title, 370, 605)
+ ui = new(user, src, ui_key, "chem_dispenser.tmpl", ui_title, 380, 650)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
diff --git a/nano/templates/apc.tmpl b/nano/templates/apc.tmpl
index 446ba31a145..56c6a1f1eeb 100644
--- a/nano/templates/apc.tmpl
+++ b/nano/templates/apc.tmpl
@@ -1,141 +1,174 @@
- {^{if locked}}
- Swipe ID card to unlock interface
+ {{if siliconUser}}
+
+ Interface Lock:
+
+
+ {{:~link('Engaged', 'locked', {'toggleaccess' : 1}, locked ? 'selected' : null)}}{{:~link('Disengaged', 'unlocked', {'toggleaccess' : 1}, malfStatus >= 2 ? 'linkOff' : (locked ? null : 'selected'))}}
+
+
{{else}}
- Swipe ID card to lock interface
+ {{if locked}}
+ Swipe an ID card to unlock this interface.
+ {{else}}
+ Swipe an ID card to lock this interface.
+ {{/if}}
{{/if}}
-Status
+
-
-
- Main Breaker:
-
-
- {^{if locked}}
- {^{if isOperating}}
- On
- {{else}}
- Off
- {{/if}}
- {{else}}
- {^{:~link('On', {'breaker' : 1}, isOperating ? 'selected' : null)}}{^{:~link('Off', {'breaker' : 1}, isOperating ? null : 'selected')}}
- {{/if}}
-
-
+
Power Status
-
-
- External Power:
-
-
- {^{if externalPower == 2}}
- Good
- {{else externalPower == 1}}
- Low
- {{else}}
- None
- {{/if}}
-
-
-
-
-
- Power Cell:
-
-
- {^{if powerCellStatus == null}}
- Not connected.
- {{else}}
- {^{:powerCellStatus}}%
- {{/if}}
-
-
-
-{^{if powerCellStatus != null}}
- Charge Mode:
+ Main Breaker:
- {^{if locked}}
- {^{if chargeMode}}
- Auto
+ {{if locked && !siliconUser}}
+ {{if isOperating}}
+ On
{{else}}
Off
- {{/if}}
+ {{/if}}
{{else}}
- {^{:~link('Auto', {'cmode' : 1}, chargeMode ? 'selected' : null)}}{^{:~link('Off', {'cmode' : 1}, chargeMode ? null : 'selected')}}
- {{/if}}
-
- {^{if chargingStatus > 1}}
- (Fully Charged)
- {{else chargingStatus == 1}}
- (Charging)
- {{else}}
- (Not Charging)
+ {{:~link('On', 'power', {'breaker' : 1}, isOperating ? 'selected' : null)}}{{:~link('Off', 'close', {'breaker' : 1}, isOperating ? null : 'selected')}}
{{/if}}
-{{/if}}
-
Power Channels
-
-{^{for powerChannels}}
- {^{:title}}
+ External Power:
-
- {^{:powerLoad}} W
-
-
- {^{if !~root.locked}}
- {^{:~link('Auto', topicParams.auto, (status == 1 || status == 3) ? 'selected' : null)}}
- {^{:~link('On', topicParams.on, (status == 2) ? 'selected' : null)}}
- {^{:~link('Off', topicParams.off, (status == 0) ? 'selected' : null)}}
- {{/if}}
- {^{if status <= 1}}
- Off
- {{else status >= 2}}
- On
- {{/if}}
- {^{if ~root.locked}}
- {^{if status == 1 || status == 3}}
- (Auto)
- {{else}}
- (Manual)
- {{/if}}
- {{/if}}
-
-
-{{/for}}
-
-
-
-
-
- Total Load:
-
-
- {{:totalLoad}} W
-
-
-
-
-
- Cover Lock:
-
-
- {^{if locked}}
- {^{if coverLocked}}
-
Engaged
+
+ {{if externalPower == 2}}
+ Good
+ {{else externalPower == 1}}
+ Low
{{else}}
- Disengaged
+ None
{{/if}}
+
+
+
+
+
+ Power Cell:
+
+ {{if powerCellStatus == null}}
+
+ Power cell removed.
+
{{else}}
- {^{:~link('Engaged', {'lock' : 1}, coverLocked ? 'selected' : null)}}{^{:~link('Disengaged', {'lock' : 1}, coverLocked ? null : 'selected')}}
+
+ {{:~round(powerCellStatus*10)/10}}%
+
+ {{:~displayBar(powerCellStatus, 0, 100, powerCellStatus >= 50 ? 'good' : powerCellStatus >= 25 ? 'average' : 'bad')}}
{{/if}}
-
\ No newline at end of file
+
+ {{if powerCellStatus != null}}
+
+
+ Charge Mode:
+
+
+ {{if locked && !siliconUser}}
+ {{if chargeMode}}
+ Auto
+ {{else}}
+ Off
+ {{/if}}
+ {{else}}
+ {{:~link('Auto', 'refresh', {'cmode' : 1}, chargeMode ? 'selected' : null)}}{{:~link('Off', 'close', {'cmode' : 1}, chargeMode ? null : 'selected')}}
+ {{/if}}
+
+ {{if chargingStatus > 1}}
+ [Fully Charged]
+ {{else chargingStatus == 1}}
+ [Charging]
+ {{else}}
+ [Not Charging]
+ {{/if}}
+
+
+ {{/if}}
+
+
+
Power Channels
+
+ {{for powerChannels}}
+
+
+ {{:title}}:
+
+
+ {{:powerLoad}} W
+
+
+
+ {{if status <= 1}}
+ Off
+ {{else status >= 2}}
+ On
+ {{/if}}
+ {{if status == 1 || status == 3}}
+ [Auto]
+ {{else}}
+ [Manual]
+ {{/if}}
+
+ {{if !~root.locked || ~root.siliconUser}}
+
+ {{:~link('Auto', 'refresh', topicParams.auto, (status == 1 || status == 3) ? 'selected' : null)}}
+ {{:~link('On', 'power', topicParams.on, (status == 2) ? 'selected' : null)}}
+ {{:~link('Off', 'close', topicParams.off, (status == 0) ? 'selected' : null)}}
+
+ {{/if}}
+
+ {{/for}}
+
+
+
+ Total Load:
+
+
+ {{:totalLoad}} W
+
+
+
+
+
+
+
+ Cover Lock:
+
+
+ {{if locked && !siliconUser}}
+ {{if coverLocked}}
+ Engaged
+ {{else}}
+ Disengaged
+ {{/if}}
+ {{else}}
+ {{:~link('Engaged', 'locked', {'lock' : 1}, coverLocked ? 'selected' : null)}}{{:~link('Disengaged', 'unlocked', {'lock' : 1}, coverLocked ? null : 'selected')}}
+ {{/if}}
+
+
+
+ {{if siliconUser}}
+
System Overrides
+
+
+ {{:~link('Overload Lighting Circuit', 'lightbulb', {'overload' : 1})}}
+ {{if malfStatus == 1}}
+ {{:~link('Override Programming', 'script', {'malfhack' : 1})}}
+ {{else malfStatus > 1}}
+
APC Hacked
+ {{/if}}
+
+ {{/if}}
+
+
+
\ No newline at end of file