Advertisement
elijahlorden

InstallData

Jul 17th, 2017
2,633
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 157.59 KB | None | 0 0
  1. {"1":{"\/drivers\/Terminal":"local Tablet = {}\r\n\r\nTablet.init = function()\r\n\tevent.timer(10, Tablet.sendKeepalive, math.huge)\r\nend\r\n\r\nTablet.load = function()\r\n\t\r\nend\r\n\r\nTablet.registerCommands = function()\r\n\t\r\nend\r\n\r\nTablet.setup = function()\r\n\t\r\nend\r\n\r\nTablet.sendKeepalive = function()\r\n\tnetwork.sendKeepalivePacket()\r\nend\r\n\r\nTablet.powerOff = function()\r\n\t\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Tablet","\/drivers\/Fusion_Reactor":"local FusionReactor = {}\r\n\r\nFusionReactor.init = function()\r\n\tevent.timer(5, FusionReactor.loopFunc, math.huge)\r\n\tnetwork.registerPingListener()\r\nend\r\n\r\nFusionReactor.defaultComponents = {\r\n\tlaserCharge = {Value = \"\", Desc = \"Redstone, Laser charge interrupt (off = not charging)\"}; -- Redstone (off = not charging)\r\n\tlaserReader = {Value = \"\", Desc = \"Adapter, Laser Amplifier\"}; -- Adapter attacked to laser emitter\r\n\tlaserFire = {Value = \"\", Desc = \"Redstone, Laser firing signal (on = fire)\"}; -- Redstone (on = fire)\r\n\treactorInterface = {Value = \"\", Desc = \"Adapter, Reactor Logic Adapter\"}; -- Adapter attached to reactor logic adapter\r\n\tmixInjector = {Value = \"\", Desc = \"Redstone, DT Mix injector signal (on = inject)\"}; -- Redstone (on = fire)\r\n}\r\n\r\nFusionReactor.load = function(config)\r\n\tif (not config.FusionComponents) then\r\n\t\tconfig.FusionComponents = FusionReactor.defaultComponents \r\n\tend\r\n\tfor i,p in pairs(FusionReactor.defaultComponents) do\r\n\t\tconfig.FusionComponents[i] = config.FusionComponents[i] or p\r\n\tend\r\nend\r\n\r\nFusionReactor.registerCommands = function()\r\n\tCommands.registerCommand(\"injectionRate\", FusionReactor.injectionRateFunc, \"View\/Set Reactor injection rate\", \"[rate]\")\r\n\tCommands.registerCommand(\"ignite\", FusionReactor.igniteFunc, \"Ignite Fusion Reactor (Will only fire if reactor is charged and ready to ignite)\", \"[delay]\")\r\n\tCommands.registerCommand(\"stop\", FusionReactor.stopFunc, \"Set injection rate to zero\", \"\")\r\n\tCommands.registerCommand(\"startCharging\", FusionReactor.startChargingFunc, \"Enable Reactor Laser charging circuit\", \"\")\r\n\tCommands.registerCommand(\"stopCharging\", FusionReactor.stopChargingFunc, \"Disable Reactor Laser charging circuit\", \"\")\r\n\tCommands.registerCommand(\"setCompAddress\", FusionReactor.setCompAddressFunc, \"Set reactor control component addresses\", \"name, UUID\")\r\n\tCommands.registerCommand(\"listCompAddresses\", FusionReactor.listComponentsFunc, \"Print list of Fusion Reactor component addresses\", \"\")\r\n\tCommands.registerCommand(\"status\", FusionReactor.statusFunc, \"Print status of Fusion Reactor and laser assembly\", \"\")\r\n\tCommands.registerCommand(\"injectMix\", FusionReactor.injectMixFunc, \"Enable D-T injection directly into the reactor chamber\", \"[duration (defaults to 0.1)]\")\r\n\tCommands.registerCommand(\"stopInjectingMix\", FusionReactor.stopInjectingMixFunc, \"Emergency shutoff for Mix Injector\", \"\")\r\nend\r\n\r\nFusionReactor.setup = function()\r\n\t\r\nend\r\n\r\nFusionReactor.injectionRateFunc = function(response, num)\r\n\tlocal c = FusionReactor.getComponentProxy(\"reactorInterface\")\r\n\tif (not c) then response:print(\"No reactorInterface detected\") response:flush() response:sendFailure() return true end\r\n\tif (num == nil) then\r\n\t\tresponse:print(\"Current injection rate: \"..c.getInjectionRate())\r\n\t\treturn true\r\n\tend\r\n\tnum = tonumber(num) or 0\r\n\tc.setInjectionRate(num)\r\n\tresponse:print(\"Set injection rate to \"..num)\r\n\treturn true\r\nend\r\n\r\nFusionReactor.igniteFunc = function(response, delay)\r\n\tlocal c = FusionReactor.getComponentProxy(\"laserFire\")\r\n\tif (not c) then response:print(\"No laserFire detected\") response:flush() response:sendFailure() return true end\r\n\tlocal r = FusionReactor.getComponentProxy(\"reactorInterface\")\r\n\tif (not r) then response:print(\"No reactorInterface detected\") response:flush() response:sendFailure() return true, response end\r\n\tdelay = math.max(5,tonumber(delay) or 5)\r\n\tresponse:print(\"Preparing to ignite reactor\")\r\n\tevent.timer(delay, function()\r\n\t\tfor i=0,5 do\r\n\t\t\tc.setOutput(i,15)\r\n\t\tend\r\n\t\tShell.print(\"Fusion Reactor Ignition Laser has Fired\")\r\n\t\tnetwork.notifications.broadcast(\"Fusion Reactor Ignition Laser has Fired\")\r\n\tend)\r\n\tevent.timer(delay+0.5, function()\r\n\t\tfor i=0,5 do\r\n\t\t\tc.setOutput(i,0)\r\n\t\tend\r\n\tend)\r\n\tevent.timer(delay+5, function()\r\n\t\tif (r.isIgnited) then\r\n\t\t\tShell.print(\"Fusion Reactor has successfully ignited\")\r\n\t\t\tnetwork.notifications.broadcast(\"Fusion Reactor has successfully ignited\")\r\n\t\telse\r\n\t\t\tShell.print(\"Fusion Reactor ignition has failed\")\r\n\t\t\tnetwork.notifications.broadcast(\"Fusion Reactor ignition has failed\")\r\n\t\tend\r\n\tend)\r\n\treturn true\r\nend\r\n\r\nFusionReactor.stopFunc = function(response)\r\n\tlocal c = FusionReactor.getComponentProxy(\"reactorInterface\")\r\n\tif (not c) then response:print(\"No reactorInterface detected\") response:flush() response:sendFailure() return true end\r\n\tc.setInjectionRate(0)\r\n\tresponse:print(\"Reactor Injectors deactivated\")\r\n\treturn true\r\nend\r\n\r\nFusionReactor.injectMixFunc = function(response, duration)\r\n\tduration = math.max(0.1, tonumber(duration) or 0.1)\r\n\tlocal c = FusionReactor.getComponentProxy(\"mixInjector\")\r\n\tif (not c) then response:print(\"No mixInjector detected\") response:flush() response:sendFailure() return true end\r\n\tfor i=0,5 do\r\n\t\tc.setOutput(i,15)\r\n\tend\r\n\tresponse:print(\"Mix Injector activated for \"..duration..\" seconds\")\r\n\tevent.timer(duration, function()\r\n\t\tfor i=0,5 do\r\n\t\t\tc.setOutput(i,0)\r\n\t\tend\r\n\t\tShell.print(\"Mix Injector deactivated\")\r\n\tend)\r\n\treturn true\r\nend\r\n\r\nFusionReactor.stopInjectingMixFunc = function()\r\nlocal response = newResponse()\r\n\tlocal c = FusionReactor.getComponentProxy(\"mixInjector\")\r\n\tif (not c) then response:print(\"No mixInjector detected\") response:flush() response:sendFailure() return true end\r\n\tfor i=0,5 do\r\n\t\tc.setOutput(i,0)\r\n\tend\r\n\tresponse:print(\"Mix Injector deactivated\")\r\n\treturn true\r\nend\r\n\r\nFusionReactor.startChargingFunc = function(response)\r\n\tlocal c = FusionReactor.getComponentProxy(\"laserCharge\")\r\n\tif (not c) then response:print(\"No laserCharge detected\") response:flush() response:sendFailure() return true end\r\n\tif (c.getOutput(0) > 1) then response.print(\"Laser charging circuit already activated\") response:flush() response:sendFailure() return true end\r\n\tfor i=0,5 do\r\n\t\tc.setOutput(i,15)\r\n\tend\r\n\tresponse:print(\"Laser charging circuit activated\")\r\n\treturn true\r\nend\r\n\r\nFusionReactor.stopChargingFunc = function(response)\r\n\tlocal c = FusionReactor.getComponentProxy(\"laserCharge\")\r\n\tif (not c) then response.print(\"No laserCharge detected\") response:flush() response:sendFailure() return true end\r\n\tif (c.getOutput(0) < 1) then response:print(\"Laser charging circuit already deactivated\") response:flush() response:sendFailure() return true end\r\n\tfor i=0,5 do\r\n\t\tc.setOutput(i,0)\r\n\tend\r\n\tresponse:print(\"Laser charging circuit deactivated\")\r\n\treturn true\r\nend\r\n\r\nFusionReactor.setCompAddressFunc = function(response, name, address)\r\n\tif (not name) or (not address) then return false end\r\n\tlocal addressList = Device.currentConfig.FusionComponents\r\n\tif (addressList[name]) then\r\n\t\tlocal realAddress = component.get(address)\r\n\t\tif (not realAddress) then response:print(\"Component does not exist\") response:flush() response:sendFailure() return true end\r\n\t\taddressList[name].Value = realAddress\r\n\t\tresponse:print(name..\" assigned to {\"..realAddress..\"}\")\r\n\telse\r\n\t\tresponse:print(\"Component name incorrect\")\r\n\tend\r\n\tDevice.saveConfig()\r\n\treturn true\r\nend\r\n\r\nFusionReactor.listComponentsFunc = function(response)\r\n\tfor i,p in pairs(Device.currentConfig.FusionComponents) do\r\n\t\tresponse:print(i..\" \"..p.Desc..\" {\"..p.Value..\"}\")\r\n\tend\r\n\treturn true\r\nend\r\n\r\nFusionReactor.statusFunc = function(response)\r\n\tlocal laserCharge = FusionReactor.getComponentProxy(\"laserCharge\")\r\n\tif (not laserCharge) then response.print(\"No laserCharge detected\") response:flush() response:sendFailure() return true end\r\n\tlocal reactor = FusionReactor.getComponentProxy(\"reactorInterface\")\r\n\tif (not reactor) then response.print(\"No reactorInterface detected\") response:flush() response:sendFailure() return true end\r\n\tlocal laserReader = FusionReactor.getComponentProxy(\"laserReader\")\r\n\tif (not laserReader) then response.print(\"No laserReader detected\") response:flush() response:sendFailure() return true end\r\n\t\r\n\tlocal str = \"\"\r\n\tstr = str..\" -- LASER -- \"..\"\\n\"\r\n\tlocal laserEnergy = math.floor(laserReader.getEnergy()\/1000000)\r\n\tlocal laserMaxEnergy = math.floor(laserReader.getMaxEnergy()\/1000000)\r\n\tstr = str..\"Stored Energy: \"..laserEnergy..\"MJ \\n\"\r\n\tstr = str..\"Maximum Energy: \"..laserMaxEnergy..\"MJ \\n\"\r\n\tstr = str..\"Minimum Ignition energy: 1500MJ \\n\"\r\n\tif (laserEnergy > 1500) then\r\n\t\tstr = str..\"Enough energy to ignite reaction \\n\"\r\n\telse\r\n\t\tstr = str..\"Not enough energy to ignite reaction \\n\"\r\n\tend\r\n\tstr = str..\" -- REACTOR -- \"..\"\\n\"\r\n\tif (reactor.isIgnited()) then\r\n\t\tstr = str..\" Running \"\r\n\telse\r\n\t\tstr = str..\" Not Running \"\r\n\tend\r\n\tresponse:print(str)\r\n\treturn true\r\nend\r\n\r\nFusionReactor.prevRunning = false\r\n\r\nFusionReactor.loopFunc = function()\r\n\tlocal laserCharge = FusionReactor.getComponentProxy(\"laserCharge\")\r\n\tlocal laserReader = FusionReactor.getComponentProxy(\"laserReader\")\r\n\tlocal reactor = FusionReactor.getComponentProxy(\"reactorInterface\")\r\n\tif (not laserCharge) or (not laserReader) or (not reactor) then return end\r\n\tlocal igniteEnergy = 1500\r\n\tlocal laserEnergy = math.floor(laserReader.getEnergy()\/1000000)\r\n\tif (laserEnergy > igniteEnergy) and (laserCharge.getOutput(0) > 1) then\r\n\t\tfor i=0,5 do\r\n\t\t\tlaserCharge.setOutput(i,0)\r\n\t\tend\r\n\t\tShell.print(\"Fusion Reactor Laser Assembly has completed charging cycle\")\r\n\t\tShell.print(\"Laser charging circuit deactivated\")\r\n\t\tnetwork.notifications.broadcast(\"Fusion Reactor Laser Assembly has completed charging cycle \\nLaser charging circuit deactivated\")\r\n\tend\r\n\tlocal currRunning = reactor.isIgnited()\r\n\tif (not currRunning) and (prevRunning) then \r\n\t\tShell.print(\"Fusion Reactor has deactivated\")\r\n\t\tnetwork.notifications.broadcast(\"Fusion Reactor has deactivated\")\r\n\telse\r\n\t\tprevRunning = currRunning\r\n\tend\r\nend\r\n\r\nFusionReactor.getComponent = function(name)\r\n\tlocal addressList = Device.currentConfig.FusionComponents\r\n\tif (addressList[name]) then\r\n\t\treturn addressList[name].Value\r\n\tend\r\nend\r\n\r\nFusionReactor.getComponentProxy = function(name)\r\n\tlocal addressList = Device.currentConfig.FusionComponents\r\n\tif (addressList[name]) then\r\n\t\treturn component.proxy(addressList[name].Value)\r\n\tend\r\nend\r\n\r\nFusionReactor.powerOff = function()\r\n\t\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn FusionReactor","\/drivers\/Server":"local Server = {}\r\n\r\nServer.deviceList = {[network.acceptedServerName] = {Name = network.acceptedServerName, Type = \"Server\", Address = component.modem.address, Pinged = true}} -- Name = {Name = name, Type = driverName, ConnectionTime = 0, Address = address}\r\n\r\nServer.lastPing = 0\r\nServer.pingTimeout = 10\r\n\r\nServer.connectBeep = 1500\r\nServer.disconnectBeep = 300\r\n\r\nServer.init = function()\r\n\tServer.pingDevices()\r\n\tevent.timer(40, Server.pingDevices, math.huge)\r\n\tnetwork.registerNetworkListener(Server.networkListener)\r\nend\r\n\r\nServer.load = function(config)\r\n\tif (not config.GateRegistry) then config.GateRegistry = {} end\r\n\tconfig.Name = network.acceptedServerName\r\nend\r\n\r\nServer.setup = function()\r\n\r\nend\r\n\r\n\r\nServer.powerOff = function()\r\n\r\nend\r\n\r\nServer.registerCommands = function()\r\n\tCommands.registerCommand(\"listDevices\", Server.listDeviceCmd , \"Lists currently connected devices, add TypeFilter to filter devices by type\", \"[TypeFilter]\")\r\n\tCommands.registerCommand(\"sendUpdate\", Server.updateCmd , \"Package OS currently installed on Server and send it to networked devices.\", \"[DeviceName]\")\r\n\tCommands.registerCommand(\"ping\", Server.pingCmd , \"Ping network for active devices\", \"\")\r\nend\r\n\r\nServer.pingCmd = function(response)\r\n\tresponse:print(\"Pinging network...\")\r\n\tServer.pingDevices()\r\n\treturn true, response\r\nend\r\n\r\nServer.updateCmd = function(response, deviceName)\r\n\tlocal cmdReceiver = deviceName or \"All\"\r\n\tresponse:print(\"Sending update packages to \"..cmdReceiver)\r\n\tresponse:flush()\r\n\tlocal packagedOS = Packager.packageIntoTable()\r\n\tresponse:print(\"Serializing packaged OS\")\r\n\tresponse:flush()\r\n\tOS.sleep(0.1)\r\n\tlocal serializedOS = JSON.encode(packagedOS)\r\n\tresponse:print(\"Writing packaged OS to temporary file\")\r\n\tlocal tmpProxy = component.proxy(computer.getBootAddress())\r\n\tif (tmpProxy.exists(\"\/tmp\/out_UpdatePackage\")) then tmpProxy.remove(\"\/tmp\/out_UpdatePackage\") end\r\n\tlocal handle, reason = tmpProxy.open(\"\/tmp\/out_UpdatePackage\", \"w\")\r\n\tif (not handle) then response:print(\"Error opening file (\"..reason..\")\") return end\r\n\ttmpProxy.write(handle, serializedOS)\r\n\ttmpProxy.close(handle)\r\n\tresponse:print(\"Sending file via FTP\")\r\n\tresponse:print(tmpProxy.size(\"\/tmp\/out_UpdatePackage\")..\"b\")\r\n\tresponse:flush()\r\n\tnetwork.ftp.sendFile(tmpProxy, \"\/tmp\/out_UpdatePackage\", \"UpdatePackage\", cmdReceiver)\r\n\tresponse:print(\"Update distributed\")\r\n\treturn true\r\nend\r\n\r\nServer.listDeviceCmd = function(response, typeFilter)\r\n\tlocal filter = typeFilter or \"\"\r\n\tlocal str = \"\"\r\n\tresponse:print(\"Format: &#fFFA500&#{DeviceName : DeviceType}&#fFFFFFF&#\")\r\n\tfor i,p in pairs(Server.deviceList) do\r\n\t\tif (string.find(p.Type, filter)) then\r\n\t\t\tstr = str..\"{\"..p.Name..\" : \"..p.Type..\"} \"\r\n\t\tend\r\n\tend\r\n\tresponse:print(\"&#fFFA500&#\"..str..\"&#fFFFFFF&#\")\r\n\tresponse:flush()\r\n\treturn true\r\nend\r\n\r\nServer.networkListener = function(_, localNetworkCard, remoteAddress, port, distance, packet)\r\n\tif (port ~= 0) and (port ~= Enum.Port.Keepalive) and (port ~= Enum.Port.Stargate) and (port ~= Enum.Port.General) then return end\r\n\tif (packet.Header ~= Enum.Header.SHUTDOWN) then\r\n\t\tif (Server.deviceList[packet.Sender] ~= nil) then\r\n\t\t\tServer.deviceList[packet.Sender].Pinged = true\r\n\t\t\tServer.deviceList[packet.Sender].Address = remoteAddress\r\n\t\t\t--Shell.print(packet.Sender..\" Responded to network ping\")\r\n\t\telse\r\n\t\t\tServer.deviceList[packet.Sender] = {Name = packet.Sender, Type = packet.SenderType, Address = remoteAddress, Pinged = true}\r\n\t\t\tShell.print(\"Network Device \"..packet.Sender..\" (\"..packet.SenderType..\") Connected\")\r\n\t\t\tcomputer.beep(Server.connectBeep)\r\n\t\tend\r\n\tend\r\n\r\n\tif (packet.Header == Enum.Header.SHUTDOWN) then\r\n\t\tif (Server.deviceList[packet.Sender] ~= nil) then\r\n\t\t\tServer.deviceList[packet.Sender] = nil\r\n\t\t\tShell.print(packet.Sender..\" Disconnected (Reason: Shutting Down)\")\r\n\t\t\tcomputer.beep(Server.disconnectBeep)\r\n\t\tend\r\n\telseif (packet.Header == Enum.Header.FETCHGATEREGISTRY) then\r\n\t\tif (not packet.Sender) then return end\r\n\t\tShell.print(\"GateRegistry Fetch Request\")\r\n\t\tlocal outPkt = {Header = \"GateRegistryFetched\", Registry = Device.currentConfig.GateRegistry, Receiver = packet.Sender}\r\n\t\tnetwork.sendPacket(Enum.Port.StargateResponse, outPkt, false)\r\n\telseif (packet.Header == Enum.Header.REGISTERGATE) then\r\n\t\tif (not packet.GateName) or (not packet.GateAddress) then return end\r\n\t\tDevice.currentConfig.GateRegistry[packet.GateName] = packet.GateAddress\r\n\t\tShell.print(\"Gate \"..packet.GateName..\" Registered to address \"..packet.GateAddress)\r\n\t\tServer.sendGateRegistryBroadcast()\r\n\t\tDevice.saveConfig()\r\n\telseif (packet.Header == Enum.Header.UNREGISTERGATE) then\r\n\t\tif (not packet.GateName) then return end\r\n\t\tDevice.currentConfig.GateRegistry[packet.GateName] = nil\r\n\t\tShell.print(\"Gate \"..packet.GateName..\" Unregistered\")\r\n\t\tServer.sendGateRegistryBroadcast()\r\n\t\tDevice.saveConfig()\r\n\tend\r\nend\r\n\r\nServer.sendGateRegistryBroadcast = function()\r\n\tlocal outPkt = {Header = Enum.Header.GATEREGISTRYBROADCAST, Registry = Device.currentConfig.GateRegistry}\r\n\tnetwork.sendPacket(Enum.Port.StargateResponse, outPkt, false)\r\n\tShell.print(\"Broadcasted GateRegistry update\")\r\nend\r\n\r\nServer.pingDevices = function()\r\n\tlocal outPkt = {Header = Enum.Header.SERVERPING, Registry = Device.currentConfig.GateRegistry}\r\n\tnetwork.sendPacket(Enum.Port.Keepalive, outPkt, false)\r\n\tfor i,p in pairs(Server.deviceList) do\r\n\t\tp.Pinged = false\r\n\tend\r\n\t--Shell.print(\"Pinging network...\")\r\n\r\n\tevent.timer(Server.pingTimeout, function()\r\n\t\tfor i,p in pairs(Server.deviceList) do\r\n\t\t\tif (not p.Pinged) and (p.Name ~= network.acceptedServerName) then\r\n\t\t\t\tShell.print(p.Name..\" Disconnected (Reason: Timed Out)\")\r\n\t\t\t\tcomputer.beep(Server.disconnectBeep)\r\n\t\t\t\tServer.deviceList[i] = nil\r\n\t\t\tend\r\n\t\tend\r\n\tend)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Server\r\n","\/drivers\/Tablet":"local Tablet = {}\r\n\r\nTablet.init = function()\r\n\tnetwork.registerNetworkListener(Tablet.gateNetworkListener)\r\n\tlocal fetchPkt = {Header = Enum.Header.FETCHGATEREGISTRY}\r\n\tnetwork.sendPacket(Enum.Port.Stargate, fetchPkt, false)\r\n\tnetwork.registerPingListener()\r\nend\r\n\r\nTablet.load = function(config)\r\n\tif (not config.GateRegistry) then config.GateRegistry = {} end\r\n\tif (not config.PersonalGateRegistry) then config.PersonalGateRegistry = {} end\r\nend\r\n\r\nTablet.registerCommands = function()\r\n\tCommands.registerCommand(\"dialGate\", Tablet.dialGateCommand, \"Broadcast DialOut packet for un-networked gates\", \"dialAddress\/savedAddressName [-p]\")\r\n\tCommands.registerCommand(\"closeGate\", Tablet.closeGateCommand, \"Broadcast Terminate packet for un-networked gates\", \"\")\r\n\tCommands.registerCommand(\"registerGate\", Tablet.registerGateCommand, \"Register gate to server GateRegistry\", \"name, address, [-p]\")\r\n\tCommands.registerCommand(\"unregisterGate\", Tablet.unregisterGateCommand, \"Unregister gate from server GateRegistry\", \"name, [-p]\")\r\n\tCommands.registerCommand(\"listGates\", Tablet.listGates, \"List GateRegistry cache\", \"\")\r\n\tCommands.registerCommand(\"listPersonalGates\", Tablet.listPersonalGates, \"List personal GateRegistry\", \"\")\r\n\tCommands.registerCommand(\"fetchGateRegistry\", Tablet.fetchGateRegistryCommand, \"Manually fetch GateRegistry from Server\", \"\")\r\nend\r\n\r\nTablet.registerGateCommand = function(response, gateName, address, switch1)\r\n\tgateName = tostring(gateName) or \"\"\r\n\taddress = tostring(address) or \"\"\r\n\tif (gateName == \"\") or (gateName == \" \") or (address == \"\") or (address == \" \") then return false end\r\n\tif (switch1 == \"-p\") then\r\n\t\tDevice.currentConfig.PersonalGateRegistry[gateName] = address\r\n\t\tprint(\"Personal GateRegistry updated\")\r\n\telse\r\n\t\tlocal outPkt = {Header = Enum.Header.REGISTERGATE, GateName = gateName, GateAddress = address}\r\n\t\tnetwork.sendPacket(Enum.Port.Stargate, outPkt, false)\r\n\t\tprint(\"GateRegister packet sent\")\r\n\tend\r\n\tDevice.saveConfig()\r\n\treturn true\r\nend\r\n\r\nTablet.unregisterGateCommand = function(response, gateName, switch1)\r\n\tgateName = tostring(gateName) or \"\"\r\n\tif (gateName == \"\") or (gateName == \" \") then return false end\r\n\tif (switch1 == \"-p\") then\r\n\t\tDevice.currentConfig.PersonalGateRegistry[gateName] = nil\r\n\t\tprint(\"Personal GateRegistry updated\")\r\n\telse\r\n\t\tlocal outPkt = {Header = Enum.header.UNREGISTERGATE, GateName = gateName}\r\n\t\tnetwork.sendPacket(Enum.Port.Stargate, outPkt, false)\r\n\t\tprint(\"GateUnregister packet sent\")\r\n\tend\r\n\tDevice.saveConfig()\r\n\treturn true\r\nend\r\n\r\nTablet.listGates = function(response)\r\n\tlocal num = 0\r\n\tlocal str = \"\"\r\n\tfor i,p in pairs(Device.currentConfig.GateRegistry) do\r\n\t\tstr = str..i..\" (\"..p..\")\\n\"\r\n\t\tnum = num + 1\r\n\tend\r\n\tstr = str..num..\" Registered \"\r\n\tif (num > 1) and (num ~= 0) then str=str..\"Gates\" else str=str..\"Gate\" end\r\n\tprintPaged(str)\r\n\treturn true\r\nend\r\n\r\nTablet.listPersonalGates = function(response)\r\n\tlocal num = 0\r\n\tlocal str = \"\"\r\n\tfor i,p in pairs(Device.currentConfig.PersonalGateRegistry) do\r\n\t\tstr = str..i..\" (\"..p..\")\\n\"\r\n\t\tnum = num + 1\r\n\tend\r\n\tstr = str..num..\" Registered \"\r\n\tif (num > 1) and (num ~= 0) then str=str..\"Gates\" else str=str..\"Gate\" end\r\n\tprintPaged(str)\r\n\treturn true\r\nend\r\n\r\nTablet.fetchGateRegistryCommand = function(response)\r\n\tlocal outPkt = {Header = Enum.Header.FETCHGATEREGISTRY}\r\n\tnetwork.sendPacket(Enum.Port.Stargate, outPkt, false)\r\n\tprint(\"GateRegistryFetch packet sent\")\r\n\treturn true\r\nend\r\n\r\nTablet.dialGateCommand = function(response, dialAddress, switch1)\r\n\tdialAddress = tostring(dialAddress)\r\n\tif (not dialAddress) or (dialAddress == \"\") or (dialAddress == \" \") then return false end\r\n\tlocal sendAddress = dialAddress\r\n\tif (Device.currentConfig.GateRegistry[dialAddress] ~= nil) and (switch1 ~= \"-p\") then\r\n\t\tprint(\"Found GateRegistry entry for \"..dialAddress..\" {\"..Device.currentConfig.GateRegistry[dialAddress]..\"}\")\r\n\t\tsendAddress = Device.currentConfig.GateRegistry[dialAddress]\r\n\telseif (switch1 == \"-p\") and (Device.currentConfig.PersonalGateRegistry[dialAddress] ~= nil) then\r\n\t\tprint(\"Found Personal GateRegistry entry for \"..dialAddress..\" {\"..Device.currentConfig.GateRegistry[dialAddress]..\"}\")\r\n\t\tsendAddress = Device.currentConfig.PersonalGateRegistry[dialAddress]\r\n\tend\r\n\tprint(\"Sending DialOut packet...\")\r\n\tlocal packet = {Header = Enum.Header.Gate.DIALGATE, DialAddress = sendAddress}\r\n\tnetwork.sendPacketWithoutLink(Enum.Port.Stargate, packet, true)\r\n\treturn true\r\nend\r\n\r\nTablet.closeGateCommand = function(response)\r\n\tlocal packet = {Header = Enum.Header.Gate.CLOSEGATE}\r\n\tnetwork.sendPacketWithoutLink(Enum.Port.Stargate, packet, true)\r\n\tprint(\"Sending Termination packet...\")\r\n\treturn true\r\nend\r\n\r\nlocal prevGatePacket = {Header = \"\", GateAddress = \"\"}\r\n\r\nTablet.gateNetworkListener = function(_, localNetworkCard, remoteAddress, port, distance, inpkt)\r\n\tif (not port) then return end\r\n\tif (port ~= Enum.Port.StargateResponse) and (port ~= 0) then return end\r\n\tif (not inpkt) or (type(inpkt):lower() ~= \"string\") then return end\r\n\tlocal packet = serialization.unserialize(inpkt)\r\n\tif (not packet) then return end\r\n\tif (not packet.Header) then return end\r\n\tif (packet.Receiver) then\r\n\t\tif (packet.Receiver ~= Device.currentConfig.Name) and (packet.Receiver ~= \"All\") then return end\r\n\tend\r\n\tif (packet.Header == \"GateDiallingOut\") then\r\n\t\tif (not packet.GateAddress) then return end\r\n\t\tShell.print(\"Gate \"..(packet.GateAddress or \"LOCAL_ADDRESS_ERROR\")..\" initiated outgoing dialling sequence to \"..(packet.RemoteAddress or \"REMOTE_ADDRESS_ERROR\"))\r\n\telseif (packet.Header == \"GateDiallingIn\") then\r\n\t\tif (not packet.GateAddress) then return end\r\n\t\tShell.print(\"Gate \"..(packet.GateAddress or \"LOCAL_ADDRESS_ERROR\")..\" has received incoming dialling sequence from \"..(packet.RemoteAddress or \"REMOTE_ADDRESS_ERROR\"))\r\n\telseif (packet.Header == \"GateClosing\") then\r\n\t\tif (not packet.GateAddress) then return end\r\n\t\tShell.print(\"Gate \"..(packet.GateAddress or \"LOCAL_ADDRESS_ERROR\")..\"'s connection has terminated\")\r\n\telseif (packet.Header == \"GateClosing\") then\r\n\t\tif (not packet.GateAddress) then return end\r\n\t\tShell.print(\"Gate \"..(packet.GateAddress or \"LOCAL_ADDRESS_ERROR\")..\"'s connection has terminated\")\r\n\telseif (packet.Header == \"GateConnected\") then\r\n\t\tif (not packet.GateAddress) then return end\r\n\t\tif (prevGatePacket.Header == \"GateConnected\") and (prevGatePacket.GateAddress == packet.GateAddress) then return end\r\n\t\tif (packet.Direction == \"Outgoing\") then\r\n\t\t\tShell.print(\"Gate \"..(packet.GateAddress or \"LOCAL_ADDRESS_ERROR\")..\" has established a stable connection to \"..(packet.RemoteAddress or \"REMOTE_ADDRESS_ERROR\"))\r\n\t\telse\r\n\t\t\tShell.print(\"Gate \"..(packet.GateAddress or \"LOCAL_ADDRESS_ERROR\")..\" has established a stable connection from \"..(packet.RemoteAddress or \"REMOTE_ADDRESS_ERROR\"))\r\n\t\tend\r\n\telseif (packet.Header == \"GateRegistryBroadcast\") or (packet.Header == \"GateRegistryFetched\") then\r\n\t\tif (not packet.Registry) then return end\r\n\t\tShell.print(\"Received GateRegistry update\")\r\n\t\tDevice.currentConfig.GateRegistry = packet.Registry\r\n\tend\r\n\tprevGatePacket = packet\r\nend\r\n\r\nTablet.setup = function()\r\n\r\nend\r\n\r\nTablet.sendKeepalive = function()\r\n\tnetwork.sendKeepalivePacket()\r\nend\r\n\r\nTablet.powerOff = function()\r\n\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Tablet\r\n","\/drivers\/Redstone":"local Redstone = {}\r\n\r\nRedstone.init = function()\r\n\tnetwork.registerPingListener()\r\nend\r\n\r\nRedstone.load = function()\r\n\t\r\nend\r\n\r\nRedstone.registerCommands = function()\r\n\tCommands.registerCommand(\"rs\", Redstone.rs, \"Set redstone signal on a side\", \"side, [power]\")\r\nend\r\n\r\nRedstone.rs = function(side, power)\r\n\tif (not side) then return false end\r\n\tif (not power) then\r\n\t\tif type(side) == \"string\" then\r\n\t\t\tside = Enum.Side[side]\r\n\t\tend\r\n\t\tprint(component.proxy(component.list(\"redstone\")()).getInput(side))\r\n\t\tif type(side) == \"string\" then\r\n\t\t\tside = Enum.Side[side]\r\n\t\tend\r\n\t\treturn true, response\r\n\tend\r\n\tif type(side) == \"string\" then\r\n\t\tside = Enum.Side[side]\r\n\tend\r\n\tpower = tonumber(power) or 0\r\n\tprint(component.proxy(component.list(\"redstone\")()).setOutput(side, power))\r\n\treturn true, response\r\nend\r\n\r\nRedstone.setup = function()\r\n\t\r\nend\r\n\r\nRedstone.powerOff = function()\r\n\t\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Redstone"},"2":{"\/miniapps\/GateController":"OS = {}\r\nfunction OS.sleep(timeout)\r\n\tcheckArg(1, timeout, \"number\", \"nil\")\r\n\tlocal deadline = computer.uptime() + (timeout or 0)\r\n\trepeat\r\n\t\tevent.pull(deadline - computer.uptime())\r\n\tuntil computer.uptime() >= deadline\r\nend\r\n\r\n\r\nfunction loadfile(file, mode, env)\r\n local handle, reason = filesystem.open(file)\r\n if not handle then\r\n error(reason, 2)\r\n end\r\n local buffer = \"\"\r\n repeat\r\n local data, reason = filesystem.read(handle)\r\n if not data and reason then\r\n error(reason)\r\n end\r\n buffer = buffer .. (data or \"\")\r\n until not data\r\n filesystem.close(handle)\r\n if mode == nil then mode = \"bt\" end\r\n if env == nil then env = _G end\r\n return load(buffer, \"=\" .. file)\r\nend\r\n\r\nfunction dofile(file)\r\n local program, reason = loadfile(file)\r\n if program then\r\n local result = table.pack(pcall(program))\r\n if result[1] then\r\n return table.unpack(result, 2, result.n)\r\n else\r\n error(result[2])\r\n end\r\n else\r\n error(reason)\r\n end\r\nend\r\n\r\nevent = event_code()\r\ncomponent_code()\r\ntext = text_code()\r\nfilesystem = fs_code()\r\nfs = filesystem\r\nkeyboard = dofile(\"Keyboard.lua\")\r\nterm = terminal_code()\r\n\r\nnetwork = dofile(\"network\")\r\nEnum = dofile(\"Enum\")\r\nserialization = dofile(\"serialization\")\r\n\r\nevent_code, component_code, text_code, fs_code, terminal_code = nil, nil, nil, nil, nil\r\n\r\n-- bind GPU\r\n\r\nif term.isAvailable() then\r\n component.gpu.bind(component.screen.address)\r\n component.gpu.setResolution(component.gpu.getResolution())\r\n component.gpu.setBackground(0x000000)\r\n component.gpu.setForeground(0xFFFFFF)\r\n term.setCursorBlink(true)\r\n term.clear()\r\nend\r\n\r\nnetwork.portInit()\r\nprint()\r\nprint(\"GateController Started\")\r\n\r\nsendToLinkedCards = function(packet)\r\n\tlocal tunnels = component.list(\"tunnel\", true) or {}\r\n\tfor a,t in tunnels do\r\n\t\tlocal tc = component.proxy(a)\r\n\t\ttc.send(packet)\r\n\tend\r\nend\r\n\r\nGate = component.getPrimary(\"stargate\")\r\n\r\nfunction sendOutgoingDialPacket()\r\n\tlocal packet = {Header = Enum.Header.Gate.GATEDIALLINGOUT, GateAddress = Gate.localAddress(), RemoteAddress = Gate.remoteAddress()}\r\n\tnetwork.sendPacketWithoutLink(Enum.Port.StargateResponse, packet, true)\r\nend\r\n\r\nfunction sendConnectedPacket(direction)\r\n\tlocal packet = {Header = Enum.Header.Gate.GATECONNECTED, GateAddress = Gate.localAddress(), RemoteAddress = Gate.remoteAddress(), Direction = direction}\r\n\tnetwork.sendPacketWithoutLink(Enum.Port.StargateResponse, packet, true)\r\nend\r\n\r\nfunction sendIncomingDialPacket()\r\n\tlocal packet = {Header = Enum.Header.Gate.GATEDIALLINGIN, GateAddress = Gate.localAddress(), RemoteAddress = Gate.remoteAddress()}\r\n\tnetwork.sendPacketWithoutLink(Enum.Port.StargateResponse, packet, true)\r\nend\r\n\r\nfunction sendClosingPacket()\r\n\tlocal packet = {Header = Enum.Header.Gate.GATECLOSING, GateAddress = Gate.localAddress()}\r\n\tnetwork.sendPacketWithoutLink(Enum.Port.StargateResponse, packet, true)\r\nend\r\n\r\n\r\n\r\nfunction networkListener(_, localNetworkCard, remoteAddress, port, distance, inpkt)\r\n\tif (not inpkt) then return end\r\n\tif (port ~= Enum.Port.Stargate) and (port ~= Enum.Port.General) then return end\r\n\t--print(\"Gate-related packet received \"..port)\r\n\tlocal packet = serialization.unserialize(inpkt)\r\n\tif (not packet) then return end\r\n\tif (not packet.Header) then return end\r\n\tif (packet.Header == \"dialGate\") then\r\n\t\tif (not packet.DialAddress) then return end\r\n\t\tprint(\"Dial packet received {\"..packet.DialAddress..\"}\")\r\n\t\tGate.dial(packet.DialAddress)\r\n\telseif (packet.Header == \"closeGate\") then\r\n\t\tlocal state, engaged, direction = Gate.stargateState()\r\n\t\tif (state == \"Dialling\") or (state == \"Connected\") or (state == \"Opening\") then\r\n\t\t\tprint(\"Terminate packet received\")\r\n\t\t\tGate.disconnect()\r\n\t\tend\r\n\telseif (packet.Header == \"sendGDO\") then\r\n\r\n\tend\r\nend\r\n\r\nlocal lastGateEvent = \"\"\r\nlocal lastGateState = \"\"\r\n\r\nfunction gateEvent(tArgs)\r\n\tif (tArgs[1] == \"sgDialIn\") then\r\n\t\tsendIncomingDialPacket()\r\n\telseif (tArgs[1] == \"sgDialOut\") then\r\n\t\tsendOutgoingDialPacket()\r\n\telseif (tArgs[1] == \"sgStargateStateChange\") then\r\n\t\tlocal newState = tArgs[3]\r\n\t\tlocal oldState = tArgs[4]\r\n\t\tlocal _,_,direction = Gate.stargateState()\r\n\t\tif (lastGateState ~= newState) then\r\n\t\t\tif (newState == \"Connected\") then sendConnectedPacket(direction) return end\r\n\t\t\tif (newState == \"Closing\") or ((newState == \"Offline\") and (oldState == \"Closing\")) then sendClosingPacket() return end\r\n\t\tend\r\n\t\tlastGateState = newState\r\n\telseif (tArgs[1] == \"sgMessageReceived\") then\r\n\r\n\tend\r\n\tlastGateEvent = tArgs[1]\r\nend\r\n\r\nwhile true do\r\n\tlocal tEvent = table.pack(event.pull())\r\n\tif (tEvent[1] == \"modem_message\") then\r\n\t\tnetworkListener(table.unpack(tEvent))\r\n\telse\r\n\t\tgateEvent(tEvent)\r\n\tend\r\nend\r\n","\/miniapps\/LinkedRelay":"function loadfile(file, mode, env)\r\n local handle, reason = filesystem.open(file)\r\n if not handle then\r\n error(reason, 2)\r\n end\r\n local buffer = \"\"\r\n repeat\r\n local data, reason = filesystem.read(handle)\r\n if not data and reason then\r\n error(reason)\r\n end\r\n buffer = buffer .. (data or \"\")\r\n until not data\r\n filesystem.close(handle)\r\n if mode == nil then mode = \"bt\" end\r\n if env == nil then env = _G end\r\n return load(buffer, \"=\" .. file)\r\nend\r\n\r\nfunction dofile(file)\r\n local program, reason = loadfile(file)\r\n if program then\r\n local result = table.pack(pcall(program))\r\n if result[1] then\r\n return table.unpack(result, 2, result.n)\r\n else\r\n error(result[2])\r\n end\r\n else\r\n error(reason)\r\n end\r\nend\r\n\r\nevent = event_code()\r\ncomponent_code()\r\ntext = text_code()\r\nfilesystem = fs_code()\r\nfs = filesystem\r\nkeyboard = dofile(\"Keyboard.lua\")\r\nterm = terminal_code()\r\n\r\nnetwork = dofile(\"network\")\r\nserialization = dofile(\"serialization\")\r\n\r\nevent_code, component_code, text_code, fs_code, terminal_code = nil, nil, nil, nil, nil\r\n\r\n-- bind GPU\r\n\r\nif term.isAvailable() then\r\n component.gpu.bind(component.screen.address)\r\n component.gpu.setResolution(component.gpu.getResolution())\r\n component.gpu.setBackground(0x000000)\r\n component.gpu.setForeground(0xFFFFFF)\r\n term.setCursorBlink(true)\r\n term.clear()\r\nend\r\n\r\nnetwork.portInit()\r\nprint()\r\nprint(\"LinkedRelay Started\")\r\n\r\nsendToLinkedCards = function(packet)\r\n\tlocal tunnels = component.list(\"tunnel\", true) or {}\r\n\tfor a,t in tunnels do\r\n\t\tlocal tc = component.proxy(a)\r\n\t\ttc.send(packet)\r\n\tend\r\nend\r\n\r\nwhile true do\r\n\t_, localNetworkCard, remoteAddress, port, distance, inpkt = event.pull(\"modem_message\")\r\n\t--print(\"message on port \"..port)\r\n\tif (port == 0) then\r\n\t\tlocal desPkt = serialization.unserialize(inpkt)\r\n\t\tif (not desPkt) then return end\r\n\t\tlocal sendPort = Enum.Port[desPkt.PortName] or Enum.Port.General\r\n\t\tcomponent.modem.broadcast(sendPort, inpkt)\r\n\t\tprint(\"Received Linked Message, forwarding to network (Port \"..sendPort..\")\")\r\n\telse\r\n\t\tsendToLinkedCards(inpkt)\r\n\t\tprint(\"Received network message on Port \"..port..\", forwarding to linked card\")\r\n\tend\r\nend\r\n"},"3":{"\/modules\/Commands":"Commands = {}\r\n\r\nCommands.commandList = {}\r\n\r\nCommands.nCommands = 0\r\n\r\nCommands.busy = false\r\n\r\nCommands.registerCommand = function(name, func, helpDesc, helpArgs)\r\n\tlocal tbl = {}\r\n\ttbl.Name = name\r\n\ttbl.Function = func\r\n\ttbl.Description = helpDesc or \"\"\r\n\ttbl.ArgumentMessage = helpArgs or \"\"\r\n\tCommands.commandList[name] = tbl\r\n\tCommands.nCommands = Commands.nCommands + 1\r\nend\r\n\r\nCommands.executeCommand = function(name, netPacket, ...)\r\n\tCommands.busy = true\r\n\tlocal response;\r\n\tif (netPacket) then\r\n\t\tresponse = newResponse(netPacket)\r\n\telse\r\n\t\tresponse = newResponse(nil)\r\n\tend\r\n\tresponse:sendAck()\r\n\tif (Commands.commandList[name] ~= nil) then\r\n\t\tlocal success = Commands.commandList[name].Function(response, ...)\r\n\t\tif (not success) then\r\n\t\t\tresponse:print(\"&#fB3B3B3&#\"..Commands.commandList[name].Description)\r\n\t\t\tresponse:print(\"Usage: &#fADD8E6&#\"..Commands.commandList[name].Name..\" &#fB3B3B3&#\"..Commands.commandList[name].ArgumentMessage..\"&#fFFFFFF&#\")\r\n\t\t\tif (string.find(Commands.commandList[name].ArgumentMessage, \"%]\")) then\r\n\t\t\t\tresponse:print(\"&#fB3B3B3&#[ ] = optional parameter&#fFFFFFF&#\")\r\n\t\t\tend\r\n\t\t\tresponse:flush()\r\n\t\t\tresponse:sendFailure()\r\n\t\telse\r\n\t\t\tresponse:flush()\r\n\t\t\tresponse:sendSuccess()\r\n\t\tend\r\n\telse\r\n\t\tresponse:print(Formatters.formatError(\"'\"..tostring(name)..\"' is not a valid Command. For a list of Commands, run 'help'\"))\r\n\t\tresponse:flush()\r\n\t\tresponse:sendFailure()\r\n\tend\r\n\tCommands.busy = false\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n----------------------------------------------------------------- Internal Commands\r\nlocal helpFunc = function(response, cmdName) -- HELP\r\n\tif (cmdName == nil) then\r\n\t\tlocal str = \"\"\r\n\t\tlocal c = 0\r\n\t\tfor i,p in pairs(Commands.commandList) do\r\n\t\t\tc = c + 1\r\n\t\t\tif (c == Commands.nCommands) then\r\n\t\t\t\tstr = str..\"&#fADD8E6&#\"..p.Name..\"&#fFFFFFF&#\"\r\n\t\t\telse\r\n\t\t\t\tstr = str..\"&#fADD8E6&#\"..p.Name..\"&#f00FF00&#, \"\r\n\t\t\tend\r\n\t\tend\r\n\t\tresponse:print(str)\r\n\t\tresponse:flush()\r\n\telse\r\n\t\tif (Commands.commandList[cmdName] ~= nil) then\r\n\t\t\tresponse:print(\"&#fB3B3B3&#\"..Commands.commandList[cmdName].Description)\r\n\t\t\tresponse:print(\"Usage: &#fADD8E6&#\"..Commands.commandList[cmdName].Name..\" &#fB3B3B3&#\"..Commands.commandList[cmdName].ArgumentMessage..\"&#fFFFFFF&#\")\r\n\t\t\tif (string.find(Commands.commandList[cmdName].ArgumentMessage, \"%]\")) then\r\n\t\t\t\tresponse:print(\"&#fB3B3B3&#[ ] = optional parameter&#fFFFFFF&#\")\r\n\t\t\tend\r\n\t\t\tresponse:flush()\r\n\t\telse\r\n\t\t\tresponse:print(\"'\"..tostring(cmdName)..\"' is not a valid Command. For a list of Commands, run 'help'\")\r\n\t\t\tresponse:flush()\r\n\t\tend\r\n\tend\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"help\", helpFunc, \"Displays command list\", \"[command]\")\r\n\r\nlocal deviceNameFunc = function(response, newName) -- SET DEVICE NAME\r\n\tif (Device.currentConfig.Driver == \"Server\") then response:print(\"Unable to rename Central Server\") response:flush() response:sendFailure() return true end\r\n\tlocal newName = tostring(newName)\r\n\tif (newName == nil) or (newName == \"\") or (newName == \" \") then return false end\r\n\tif (newName:len() > 25) or (newName:len() < 5) then response:print(\"Name must 5 to 25 characters long\") response:flush() return true end\r\n\tDevice.currentConfig.Name = newName\r\n\tresponse:print(\"Device name changed to '\"..Device.currentConfig.Name..\"'\")\r\n\tresponse:flush()\r\n\tDevice.saveConfig()\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"setDeviceName\", deviceNameFunc, \"Sets name of local device\", \"name\")\r\n\r\nlocal deviceDriverFunc = function(response, newDriver) -- SET DEVICE DRIVER\r\n\tlocal newDriver = tostring(newDriver)\r\n\tif (newDriver == nil) or (newDriver == \"\") or (newDriver == \" \") then return false end\r\n\tif (Device.driverList[newDriver] == nil) then response:print(\"Driver does not exist\") response:flush() response:sendFailure() return true end\r\n\tDevice.currentConfig.Driver = newDriver\r\n\tresponse:print(\"Device driver changed to '\"..Device.currentConfig.Driver..\"'\")\r\n\tresponse:print(\"A reboot will be required for the change to take effect\")\r\n\tDevice.saveConfig()\r\n\tresponse:flush()\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"setDeviceDriver\", deviceDriverFunc, \"Sets driver of local device\", \"driverName\")\r\n\r\nCommands.registerCommand(\"listDeviceDrivers\", function(res) for i,p in pairs(Device.driverList) do print(i..\" -- \"..p.desc) res.print(i..\" -- \"..p.desc) end return true, res end, \"List available device drivers\", \"\")\r\n\r\nCommands.registerCommand(\"memory\", function(res) res:print(OS.memoryMsgStr()) res:flush() return true end, \"Displays memory status\", \"\")\r\n\r\nCommands.registerCommand(\"energy\", function(res) res:print(OS.powerMsgStr()) res:flush() return true end, \"Displays energy status\", \"\")\r\n\r\nCommands.registerCommand(\"shutdown\", function(res) res:print(\"Shutting Downn\") res:flush() res:sendSuccess() OS.sleep(1) network.sendShutdownPacket() Device.saveConfig() if (Device.Driver) then Device.Driver.powerOff() end computer.shutdown() return true end, \"Soft poweroff\", \"\")\r\n\r\nlocal rebootCommand = function(response)\r\n\tif (Device.updatePackage ~= nil) then\r\n\t\tresponse:print(\"Update package present, installation process beginning\")\r\n\t\tresponse:print(\"Do NOT power off the machine during the update process.\")\r\n\t\tresponse:print(\"If the machine is powered off during the update process, it will no longer function correctly.\")\r\n\t\tresponse:print(\"Commencing update...\")\r\n\t\tOS.sleep(1)\r\n\t\tPackager.installUpdatePackage(Device.updatePackage)\r\n\t\tresponse:print(\"Rebooting\")\r\n\t\tresponse:flush()\r\n\t\tresponse:sendSuccess()\r\n\t\tOS.sleep(3)\r\n\t\tnetwork.sendShutdownPacket()\r\n\t\tDevice.saveConfig()\r\n\t\tif (Device.Driver) then Device.Driver.powerOff() end\r\n\t\tcomputer.shutdown(true)\r\n\telse\r\n\t\tresponse:print(\"Rebooting\")\r\n\t\tresponse:flush()\r\n\t\tresponse:sendSuccess()\r\n\t\tOS.sleep(1)\r\n\t\tnetwork.sendShutdownPacket()\r\n\t\tDevice.saveConfig()\r\n\t\tif (Device.Driver) then Device.Driver.powerOff() end\r\n\t\tcomputer.shutdown(true)\r\n\tend\r\nend\r\n\r\nCommands.registerCommand(\"reboot\", rebootCommand, \"Soft reboot, will install update package if available\", \"\")\r\n\r\nCommands.registerCommand(\"cls\", function() term.clear() return true end, \"Clears the screen\", \"\")\r\n\r\nlocal listDrives = function(response) -- LIST DRIVES\r\n\tlocal driveIter = fs.drive.list()\r\n\tlocal num = 0\r\n\tfor d in driveIter do\r\n\t\tnum = num + 1\r\n\t\tlocal address = fs.drive.toAddress(d)\r\n\t\tlocal proxy = fs.drive.letterToProxy(d)\r\n\t\tif (proxy) then\r\n\t\t\tresponse:print((d or \"Drive_Letter_Error\")..\" \"..(\"[\"..(proxy.getLabel() or \"No Label\")..\"]\")..\" (\"..(address or \"Address_Error\")..\")\")\r\n\t\tend\r\n\tend\r\n\tresponse:print(num..\" Drives\")\r\n\tresponse:flush()\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"listDrives\", listDrives, \"List currently attached drives\", \"\")\r\n\r\nlocal installFunc = function(response, driveLetter) -- INSTALL TO DRIVE\r\n\tlocal driveLetter = tostring(driveLetter):sub(1,1):upper() or \"\"\r\n\tif (not driveLetter) or (driveLetter == \"\") or (driveLetter == \" \") then return false end\r\n\tresponse:print(\"Attempting to install OS on drive \"..driveLetter)\r\n\tlocal success = Packager.installToDrive(driveLetter)\r\n\tif (success) then response:print(\"Installation successful\") response:flush() else response:print(\"Installation Failed\") response:flush() response:sendSuccess() end\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"install\", installFunc, \"Install OS to the specified drive\", \"driveLetter\")\r\n\r\nlocal createInstallerFunc = function(response, driveLetter) -- CREATE INSTALLER FILES\r\n\tlocal driveLetter = tostring(driveLetter):sub(1,1):upper() or \"\"\r\n\tif (not driveLetter) or (driveLetter == \"\") or (driveLetter == \" \") then return false end\r\n\tlocal proxy = fs.drive.letterToProxy(driveLetter)\r\n\tif (not proxy) then response:print(\"Drive does not exist\") response:flush() response:sendFailure() return true end\r\n\tresponse:print(\"Creating installer files on drive \"..driveLetter)\r\n\tresponse:flush()\r\n\tlocal insProg, insData = Packager.assembleInstallFiles()\r\n\tPackager.writeFile(proxy, \"\/Installer\", insProg)\r\n\tPackager.writeFile(proxy, \"\/InstallData\", insData)\r\n\tresponse:print(\"Installer files written\")\r\n\tresponse:flush()\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"createInstallFiles\", createInstallerFunc, \"Create installer files\", \"driveLetter\")\r\n\r\nlocal installMiniappFunc = function(response, driveLetter, appName)\r\n\tif (not appName) or (appName == \"\") or (appName == \" \") then return false end\r\n\tlocal driveLetter = tostring(driveLetter):sub(1,1):upper() or \"\"\r\n\tif (not driveLetter) or (driveLetter == \"\") or (driveLetter == \" \") then return false end\r\n\tif (Device.miniAppList[appName] ~= nil) then\r\n\t\tlocal file = \"\/miniapps\/\"..Device.miniAppList[appName].file\r\n\t\tif (not filesystem.exists(file)) then response:print(\"App file not found\") response:flush() response:sendFailure() return true end\r\n\t\tif (not Packager.installMiniAppToDrive(driveLetter, file)) then response:print(\"Installation Failed\") response:flush() response:sendFailure() return true end\r\n\t\tresponse:print(\"Installed \"..appName..\" on drive \"..driveLetter)\r\n\t\tresponse:flush()\r\n\t\tlocal proxy = fs.drive.letterToProxy(driveLetter)\r\n\t\tif (proxy) then proxy.setLabel(\"ma:\"..appName) end\r\n\tend\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"installMiniApp\", installMiniappFunc, \"Install a MiniApplication to the specified drive\", \"driveLetter, appName\")\r\n\r\nCommands.registerCommand(\"listMiniApps\", function(res) for i,p in pairs(Device.miniAppList) do res:print(i..\" -- \"..p.desc) end res:flush() return true end, \"List available device drivers\", \"\")\r\n\r\nlocal listComponentMethodsFunc = function(response, uuid) -- Print list of component methods\r\n\tlocal c = component.get(uuid)\r\n\tif (not c) then\r\n\t\tresponse:print(\"Component does not exist\")\r\n\t\tresponse:flush()\r\n\t\treturn true\r\n\tend\r\n\tlocal s = serialization.serialize(component.proxy(c), 10000)\r\n\tresponse:printPaged(s)\r\n\tresponse:flush()\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"listComponentMethods\", listComponentMethodsFunc, \"List methods for component\", \"UUID (can be partial)\")\r\n\r\nlocal updateFromFileFunc = function(response, path) -- Update OS from packaged installData file\r\n\tif (not path) then return false end\r\n\tlocal proxy = fs.drive.letterToProxy(path:sub(1,1):upper() or \"\")\r\n\tif (not proxy) then response:print(\"Drive does not exist\") response:flush() response:sendFailure() return true end\r\n\tlocal success = Packager.installUpdateFromDrive(path)\r\n\tif (success) then\r\n\t\tDevice.updatePackage = nil\r\n\t\tresponse:print(\"Update completed\")\r\n\t\tresponse:flush()\r\n\telse\r\n\t\tresponse:print(\"Update failed\")\r\n\t\tresponse:flush()\r\n\t\tresponse:sendFailure()\r\n\tend\r\n\treturn true\r\nend\r\n\r\nCommands.registerCommand(\"updateFromFile\", updateFromFileFunc, \"Update local installation from file\", \"Path (absolute)\")\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Commands","\/modules\/network":"local network = {}\r\n\r\nnetwork.acceptedServerName = \"Server\"\r\n\r\nnetwork.getModem = function()\r\n\tlocal modem = component.modem\r\n\tif (not modem) then print(\"No network card attached to device\") end\r\n\treturn modem or nil\r\nend\r\n\r\nnetwork.sendToLinkedCards = function(packet)\r\n\tlocal tunnels = component.list(\"tunnel\", true) or {}\r\n\tfor a,t in tunnels do\r\n\t\tlocal tc = component.proxy(a)\r\n\t\ttc.send(packet)\r\n\tend\r\nend\r\n\r\nnetwork.sendPacket = function(port, packet, wireless)\r\n\tlocal modem = network.getModem()\r\n\tif (not modem) then return false end\r\n\tif (modem.isWireless()) then if (wireless) then modem.setStrength(100000) else modem.setStrength(0) end end\r\n\tlocal packetStr = network.formatPacket(packet, port)\r\n\tnetwork.sendToLinkedCards(packetStr)\r\n\treturn modem.broadcast(port, packetStr)\r\nend\r\n\r\nnetwork.sendPacketWithoutLink = function(port, packet, wireless)\r\n\tlocal modem = network.getModem()\r\n\tif (not modem) then return false end\r\n\tif (modem.isWireless()) then if (wireless) then modem.setStrength(100000) else modem.setStrength(0) end end\r\n\tlocal packetStr = network.formatPacket(packet, port)\r\n\treturn modem.broadcast(port, packetStr)\r\nend\r\n\r\nnetwork.getPortName = function(portNum)\r\n\tfor i,p in pairs(Enum.Port) do\r\n\t\tif (p == portNum) then return i end\r\n\tend\r\nend\r\n\r\nnetwork.formatPacket = function(inpkt, port)\r\n\tif (Device) then\r\n\t\tinpkt.SenderType = Device.currentConfig.Driver\r\n\t\tinpkt.Sender = Device.currentConfig.Name\r\n\tend\r\n\tif (not inpkt.Receiver) then inpkt.Receiver = \"All\" end\r\n\tinpkt.PortName = network.getPortName(port)\r\n\tlocal packetStr = serialization.serialize(inpkt)\r\n\treturn packetStr\r\nend\r\n\r\nnetwork.openPort = function(port)\r\n\tlocal modem = network.getModem()\r\n\tif (not modem) then return false end\r\n\t--print(\"Opening port \"..port)\r\n\treturn modem.open(port)\r\nend\r\n\r\nnetwork.closePort = function(port)\r\n\tlocal modem = network.getModem()\r\n\tif (not modem) then return false end\r\n\treturn modem.close(port)\r\nend\r\n\r\nnetwork.registerNetworkListener = function(func, name)\r\n\tevent.listen(\"WrappedNetworkSignal\", func)\r\n\tif (name) then print(\"Registered NetworkListener \"..name) end\r\nend\r\n\r\nnetwork.sendKeepalivePacket = function()\r\n\tlocal packet = {Header = Enum.Header.KEEPALIVE, Receiver = network.acceptedServerName}\r\n\tnetwork.sendPacket(Enum.Port.Keepalive, packet, false)\r\nend\r\n\r\nnetwork.sendShutdownPacket = function()\r\n\tlocal packet = {Header = Enum.Header.SHUTDOWN}\r\n\tnetwork.sendPacket(Enum.Port.Keepalive, packet, false)\r\nend\r\n\r\nnetwork.ftp = {}\r\nnetwork.notifications = {}\r\n\r\nnetwork.maxPacketSize = 7000\r\n\r\nnetwork.ftp.sendPacket = function(fileName, receiver, chunk)\r\n\tlocal packet = {Header = Enum.Header.FILETRANSFERDATA, Receiver = receiver, FileName = fileName, Chunk = chunk}\r\n\treturn network.sendPacket(Enum.Port.FTP, packet, false)\r\nend\r\n\r\nnetwork.ftp.sendFinished = function(fileName, receiver, bytes)\r\n\tlocal packet = {Header = Enum.Header.FILETRANSFERCOMPLETE, Receiver = receiver, FileName = fileName, Bytes = bytes}\r\n\treturn network.sendPacket(Enum.Port.FTP, packet, false)\r\nend\r\n\r\nnetwork.ftp.readByesFromFile = function(driveProxy, handle, bytesToRead)\r\n\tlocal buffer = \"\"\r\n\tlocal cou = 0\r\n\tlocal maxCou = math.floor(bytesToRead\/1024)-1\r\n\trepeat\r\n\t\tcou = cou + 1\r\n\t\tlocal data, reason = driveProxy.read(handle, 1024)--bytesToRead-(buffer:len()))\r\n\t\tif (not data) and (reason) then\r\n\t\t\tprint(\"Unable to read file \"..path..\"(\"..reason..\")\")\r\n\t\t\treturn\r\n\t\tend\r\n\t\tif (data) then\r\n\t\t\tbuffer = buffer..data\r\n\t\tend\r\n\tuntil (not data) or (cou > maxCou)--(buffer:len() >= bytesToRead)\r\n\tif (buffer == \"\") or (buffer == \" \") then return nil end\r\n\treturn buffer\r\nend\r\n\r\nnetwork.ftp.sendFile = function(driveProxy, path, sendName, receiverName)\r\n\tif (not driveProxy.exists(path)) or (driveProxy.isDirectory(path)) then return false end\r\n\tlocal ftpPktSize = network.maxPacketSize - 1000\r\n\tlocal handle, reason = driveProxy.open(path, \"r\")\r\n\tlocal fileSize = driveProxy.size(path)\r\n\tprint(ftpPktSize..\"b max chunk length\")\r\n\tprint(fileSize..\"b File\")\r\n\tif (not handle) then\r\n\t\tprint(\"Unable to read file \"..path..\"(\"..reason..\")\")\r\n\t\treturn\r\n\tend\r\n\trepeat\r\n\t\tlocal data = network.ftp.readByesFromFile(driveProxy, handle, ftpPktSize)\r\n\t\tif (data) then\r\n\t\t\tprint(\"Sending \"..data:len()..\"b Chunk\")\r\n\t\t\tnetwork.ftp.sendPacket(sendName, receiverName, data)\r\n\t\t\tOS.sleep(0.4)\r\n\t\tend\r\n\tuntil not data\r\n\tnetwork.ftp.sendFinished(sendName, receiverName, fileSize)\r\n\treturn true\r\nend\r\n\r\nnetwork.ftp.listener = function(_, localNetworkCard, remoteAddress, port, distance, packet)\r\n\tif (port ~= 0) and (port ~= Enum.Port.FTP) and (port ~= Enum.Port.General) then return end\r\n\tif (packet.Header == Enum.Header.FILETRANSFERDATA) then\r\n\t\tif (not packet.FileName) or (not packet.Chunk) then return end\r\n\t\tShell.print(\"Received \"..packet.Chunk:len()..\"b for file \"..packet.FileName)\r\n\t\tlocal tmpProxy = component.proxy(computer.getBootAddress())\r\n\t\tlocal handle, reason\r\n\t\tif (tmpProxy.exists(\"\/tmp\/\"..packet.FileName..\"_Partial\")) then\r\n\t\t\thandle, reason = tmpProxy.open(\"\/tmp\/\"..packet.FileName..\"_Partial\", \"a\")\r\n\t\telse\r\n\t\t\thandle, reason = tmpProxy.open(\"\/tmp\/\"..packet.FileName..\"_Partial\", \"w\")\r\n\t\tend\r\n\t\tif (not handle) then Shell.print(\"Error opening file (\"..reason..\")\") return end\r\n\t\ttmpProxy.write(handle, packet.Chunk)\r\n\t\ttmpProxy.close(file)\r\n\t\tOS.sleep(0.1)\r\n\telseif (packet.Header == Enum.Header.FILETRANSFERCOMPLETE) then\r\n\t\tif (not packet.FileName) or (not packet.Bytes) then return end\r\n\t\tlocal tmpProxy = component.proxy(computer.getBootAddress())\r\n\t\tif (tmpProxy.exists(\"\/tmp\/\"..packet.FileName..\"_Partial\")) then\r\n\t\t\tShell.print(\"Received EOF for file \"..packet.FileName)\r\n\t\t\tShell.print(\"Checking ByteCount\")\r\n\t\t\tif (tmpProxy.size(\"\/tmp\/\"..packet.FileName..\"_Partial\") == packet.Bytes) then\r\n\t\t\t\tShell.print(\"ByteCount matches, finalizing file transfer\")\r\n\t\t\t\ttmpProxy.rename(\"\/tmp\/\"..packet.FileName..\"_Partial\", \"\/tmp\/\"..packet.FileName)\r\n\t\t\t\tcomputer.pushSignal(\"ftp_file_received\", packet.FileName, \"\/tmp\/\"..packet.FileName)\r\n\t\t\telse\r\n\t\t\t\tShell.print(\"ByteCount mismath, aborting file transfer\")\r\n\t\t\t\ttmpProxy.remove(\"\/tmp\/\"..packet.FileName..\"_Partial\")\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\nend\r\n\r\nnetwork.ftp.registerFtpListener = function(func)\r\n\tevent.listen(\"ftp_file_received\", func)\r\nend\r\n\r\nnetwork.notifications.broadcast = function(message)\r\n\tlocal packet = {Header = Enum.Header.NOTIFICATION, Message = message}\r\n\tnetwork.sendPacket(Enum.Port.Notifications, packet, false)\r\nend\r\n\r\nnetwork.notifications.listener = function(_, localNetworkCard, remoteAddress, port, distance, packet)\r\n\tif (port ~= 0) and (port ~= Enum.Port.Notifications) and (port ~= Enum.Port.General) then return end\r\n\tif (not packet) then return end\r\n\tif (packet.Header ~= Enum.Header.NOTIFICATION) then return end\r\n\tif (not packet.Message) then return end\r\n\tcomputer.beep(2000)\r\n\tShell.print(\"&#fFFFF00&#\"..packet.Message..\"&#fFFFFFF&#\")\r\n\tcomputer.beep(2000)\r\nend\r\n\r\nnetwork.pingListener = function(_, localNetworkCard, remoteAddress, port, distance, packet)\r\n\tif (port ~= 0) and (port ~= Enum.Port.Keepalive) and (port ~= Enum.Port.General) then return end\r\n\tif (packet.Header ~= Enum.Header.SERVERPING) then return end\r\n\t--Shell.print(\"Responding to Server Ping\")\r\n\tnetwork.sendKeepalivePacket()\r\nend\r\n\r\nnetwork.registerPingListener = function()\r\n\tnetwork.registerNetworkListener(network.pingListener, \"PingListener\")\r\nend\r\n\r\nnetwork.wrappedNetworkSignalGenerator = function(_, localNetworkCard, remoteAddress, port, distance, inpkt)\r\n\tif (not port) then return end\r\n\tif (not inpkt) or (type(inpkt) ~= \"string\") then return end\r\n\tlocal packet = serialization.unserialize(inpkt)\r\n\tif (not packet) then return end\r\n\tif (not packet.Header) or (not packet.Sender) or (not packet.Receiver) then return end\r\n\tif (packet.Receiver ~= Device.currentConfig.Name) and (packet.Receiver ~= \"All\") then return end\r\n\t--print(inpkt)\r\n\tcomputer.pushSignal(\"WrappedNetworkSignal\", localNetworkCard, remoteAddress, port, distance, packet)\r\nend\r\n\r\n\r\nnetwork.init = function()\r\n\tevent.listen(\"modem_message\", network.wrappedNetworkSignalGenerator)\r\n\tnetwork.registerNetworkListener(network.ftp.listener)\r\n\tnetwork.registerNetworkListener(network.notifications.listener)\r\n\tnetwork.portInit()\r\nend\r\n\r\nnetwork.portInit = function()\r\n\tfor i,p in pairs(Enum.Port) do\r\n\t\tlocal success = network.openPort(p)\r\n\t\tif (success) then\r\n\t\t\tprint(\"Opened \"..i..\" Port (\"..p..\")\")\r\n\t\telse\r\n\t\t\tprint(\"Unable to open \"..i..\" Port (\"..p..\")\")\r\n\t\tend\r\n\tend\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn network\r\n","\/modules\/JSON":"-----------------------------------------------------------------------------\r\n-- JSON4Lua: JSON encoding \/ decoding support for the Lua language.\r\n-- json Module.\r\n-- Author: Craig Mason-Jones\r\n-- Homepage: http:\/\/github.com\/craigmj\/json4lua\/\r\n-- Version: 1.0.0\r\n-- This module is released under the MIT License (MIT).\r\n-- Please see LICENCE.txt for details.\r\n--\r\n-- USAGE:\r\n-- This module exposes two functions:\r\n-- json.encode(o)\r\n-- Returns the table \/ string \/ boolean \/ number \/ nil \/ json.null value as a JSON-encoded string.\r\n-- json.decode(json_string)\r\n-- Returns a Lua object populated with the data encoded in the JSON string json_string.\r\n--\r\n-- REQUIREMENTS:\r\n-- compat-5.1 if using Lua 5.0\r\n--\r\n-- CHANGELOG\r\n-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix). \r\n-- Fixed Lua 5.1 compatibility issues.\r\n-- \t\tIntroduced json.null to have null values in associative arrays.\r\n-- json.encode() performance improvement (more than 50%) through table.concat rather than ..\r\n-- Introduced decode ability to ignore \/**\/ comments in the JSON string.\r\n-- 0.9.10 Fix to array encoding \/ decoding to correctly manage nil\/null values in arrays.\r\n-----------------------------------------------------------------------------\r\n\r\n-----------------------------------------------------------------------------\r\n-- Imports and dependencies\r\n-----------------------------------------------------------------------------\r\n\r\n\r\n-----------------------------------------------------------------------------\r\n-- Module declaration\r\n-----------------------------------------------------------------------------\r\nlocal json = {} -- Public namespace\r\nlocal json_private = {} -- Private namespace\r\n\r\n-- Public constants \r\njson.EMPTY_ARRAY={} \r\njson.EMPTY_OBJECT={}\r\n\r\n-- Public functions\r\n\r\n-- Private functions\r\nlocal decode_scanArray\r\nlocal decode_scanComment\r\nlocal decode_scanConstant\r\nlocal decode_scanNumber\r\nlocal decode_scanObject\r\nlocal decode_scanString\r\nlocal decode_scanWhitespace\r\nlocal encodeString\r\nlocal isArray\r\nlocal isEncodable\r\n\r\n-----------------------------------------------------------------------------\r\n-- PUBLIC FUNCTIONS\r\n-----------------------------------------------------------------------------\r\n--- Encodes an arbitrary Lua object \/ variable.\r\n-- @param v The Lua object \/ variable to be JSON encoded.\r\n-- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)\r\nfunction json.encode (v)\r\n -- Handle nil values\r\n if v==nil then\r\n return \"null\"\r\n end\r\n \r\n local vtype = type(v)\r\n\r\n -- Handle strings\r\n if vtype=='string' then \r\n return '\"' .. json_private.encodeString(v) .. '\"'\t -- Need to handle encoding in string\r\n end\r\n \r\n -- Handle booleans\r\n if vtype=='number' or vtype=='boolean' then\r\n return tostring(v)\r\n end\r\n \r\n -- Handle tables\r\n if vtype=='table' then\r\n local rval = {}\r\n -- Consider arrays separately\r\n local bArray, maxCount = isArray(v)\r\n if bArray then\r\n for i = 1,maxCount do\r\n table.insert(rval, json.encode(v[i]))\r\n end\r\n else\t-- An object, not an array\r\n for i,j in pairs(v) do\r\n if isEncodable(i) and isEncodable(j) then\r\n table.insert(rval, '\"' .. json_private.encodeString(i) .. '\":' .. json.encode(j))\r\n end\r\n end\r\n end\r\n if bArray then\r\n return '[' .. table.concat(rval,',') ..']'\r\n else\r\n return '{' .. table.concat(rval,',') .. '}'\r\n end\r\n end\r\n \r\n -- Handle null values\r\n if vtype=='function' and v==json.null then\r\n return 'null'\r\n end\r\n \r\n assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v))\r\nend\r\n\r\n\r\n--- Decodes a JSON string and returns the decoded value as a Lua data structure \/ value.\r\n-- @param s The string to scan.\r\n-- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1.\r\n-- @param Lua object, number The object that was scanned, as a Lua table \/ string \/ number \/ boolean or nil,\r\n-- and the position of the first character after\r\n-- the scanned JSON object.\r\nfunction json.decode(s, startPos)\r\n startPos = startPos and startPos or 1\r\n startPos = decode_scanWhitespace(s,startPos)\r\n assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')\r\n local curChar = string.sub(s,startPos,startPos)\r\n -- Object\r\n if curChar=='{' then\r\n return decode_scanObject(s,startPos)\r\n end\r\n -- Array\r\n if curChar=='[' then\r\n return decode_scanArray(s,startPos)\r\n end\r\n -- Number\r\n if string.find(\"+-0123456789.e\", curChar, 1, true) then\r\n return decode_scanNumber(s,startPos)\r\n end\r\n -- String\r\n if curChar==[[\"]] or curChar==[[']] then\r\n return decode_scanString(s,startPos)\r\n end\r\n if string.sub(s,startPos,startPos+1)=='\/*' then\r\n return json.decode(s, decode_scanComment(s,startPos))\r\n end\r\n -- Otherwise, it must be a constant\r\n return decode_scanConstant(s,startPos)\r\nend\r\n\r\n--- The null function allows one to specify a null value in an associative array (which is otherwise\r\n-- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }\r\nfunction json.null()\r\n return json.null -- so json.null() will also return null ;-)\r\nend\r\n-----------------------------------------------------------------------------\r\n-- Internal, PRIVATE functions.\r\n-- Following a Python-like convention, I have prefixed all these 'PRIVATE'\r\n-- functions with an underscore.\r\n-----------------------------------------------------------------------------\r\n\r\n--- Scans an array from JSON into a Lua object\r\n-- startPos begins at the start of the array.\r\n-- Returns the array and the next starting position\r\n-- @param s The string being scanned.\r\n-- @param startPos The starting position for the scan.\r\n-- @return table, int The scanned array as a table, and the position of the next character to scan.\r\nfunction decode_scanArray(s,startPos)\r\n\tOS.sleep(0.1)\r\n local array = {}\t-- The return value\r\n local stringLen = string.len(s)\r\n assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\\n'..s )\r\n startPos = startPos + 1\r\n -- Infinite loop for array elements\r\n repeat\r\n startPos = decode_scanWhitespace(s,startPos)\r\n assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')\r\n local curChar = string.sub(s,startPos,startPos)\r\n if (curChar==']') then\r\n return array, startPos+1\r\n end\r\n if (curChar==',') then\r\n startPos = decode_scanWhitespace(s,startPos+1)\r\n end\r\n assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')\r\n object, startPos = json.decode(s,startPos)\r\n table.insert(array,object)\r\n until false\r\nend\r\n\r\n--- Scans a comment and discards the comment.\r\n-- Returns the position of the next character following the comment.\r\n-- @param string s The JSON string to scan.\r\n-- @param int startPos The starting position of the comment\r\nfunction decode_scanComment(s, startPos)\r\n\tOS.sleep(0.1)\r\n assert( string.sub(s,startPos,startPos+1)=='\/*', \"decode_scanComment called but comment does not start at position \" .. startPos)\r\n local endPos = string.find(s,'*\/',startPos+2)\r\n assert(endPos~=nil, \"Unterminated comment in string at \" .. startPos)\r\n return endPos+2 \r\nend\r\n\r\n--- Scans for given constants: true, false or null\r\n-- Returns the appropriate Lua type, and the position of the next character to read.\r\n-- @param s The string being scanned.\r\n-- @param startPos The position in the string at which to start scanning.\r\n-- @return object, int The object (true, false or nil) and the position at which the next character should be \r\n-- scanned.\r\nfunction decode_scanConstant(s, startPos)\r\n\tOS.sleep(0.1)\r\n local consts = { [\"true\"] = true, [\"false\"] = false, [\"null\"] = nil }\r\n local constNames = {\"true\",\"false\",\"null\"}\r\n\r\n for i,k in pairs(constNames) do\r\n if string.sub(s,startPos, startPos + string.len(k) -1 )==k then\r\n return consts[k], startPos + string.len(k)\r\n end\r\n end\r\n assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)\r\nend\r\n\r\n--- Scans a number from the JSON encoded string.\r\n-- (in fact, also is able to scan numeric +- eqns, which is not\r\n-- in the JSON spec.)\r\n-- Returns the number, and the position of the next character\r\n-- after the number.\r\n-- @param s The string being scanned.\r\n-- @param startPos The position at which to start scanning.\r\n-- @return number, int The extracted number and the position of the next character to scan.\r\nfunction decode_scanNumber(s,startPos)\r\n local endPos = startPos+1\r\n local stringLen = string.len(s)\r\n local acceptableChars = \"+-0123456789.e\"\r\n while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)\r\n\tand endPos<=stringLen\r\n\t) do\r\n endPos = endPos + 1\r\n end\r\n local stringValue = 'return ' .. string.sub(s,startPos, endPos-1)\r\n local stringEval = loadstring(stringValue)\r\n assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)\r\n return stringEval(), endPos\r\nend\r\n\r\n--- Scans a JSON object into a Lua object.\r\n-- startPos begins at the start of the object.\r\n-- Returns the object and the next starting position.\r\n-- @param s The string being scanned.\r\n-- @param startPos The starting position of the scan.\r\n-- @return table, int The scanned object as a table and the position of the next character to scan.\r\nfunction decode_scanObject(s,startPos)\r\nOS.sleep(0.1)\r\n local object = {}\r\n local stringLen = string.len(s)\r\n local key, value\r\n assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\\n' .. s)\r\n startPos = startPos + 1\r\n repeat\r\n startPos = decode_scanWhitespace(s,startPos)\r\n assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')\r\n local curChar = string.sub(s,startPos,startPos)\r\n if (curChar=='}') then\r\n return object,startPos+1\r\n end\r\n if (curChar==',') then\r\n startPos = decode_scanWhitespace(s,startPos+1)\r\n end\r\n assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')\r\n -- Scan the key\r\n key, startPos = json.decode(s,startPos)\r\n assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)\r\n startPos = decode_scanWhitespace(s,startPos)\r\n assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)\r\n assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)\r\n startPos = decode_scanWhitespace(s,startPos+1)\r\n assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)\r\n value, startPos = json.decode(s,startPos)\r\n object[key]=value\r\n until false\t-- infinite loop while key-value pairs are found\r\nend\r\n\r\n-- START SoniEx2\r\n-- Initialize some things used by decode_scanString\r\n-- You know, for efficiency\r\nlocal escapeSequences = {\r\n [\"\\\\t\"] = \"\\t\",\r\n [\"\\\\f\"] = \"\\f\",\r\n [\"\\\\r\"] = \"\\r\",\r\n [\"\\\\n\"] = \"\\n\",\r\n [\"\\\\b\"] = \"\\b\"\r\n}\r\nsetmetatable(escapeSequences, {__index = function(t,k)\r\n -- skip \"\\\" aka strip escape\r\n return string.sub(k,2)\r\nend})\r\n-- END SoniEx2\r\n\r\n--- Scans a JSON string from the opening inverted comma or single quote to the\r\n-- end of the string.\r\n-- Returns the string extracted as a Lua string,\r\n-- and the position of the next non-string character\r\n-- (after the closing inverted comma or single quote).\r\n-- @param s The string being scanned.\r\n-- @param startPos The starting position of the scan.\r\n-- @return string, int The extracted string as a Lua string, and the next character to parse.\r\nfunction decode_scanString(s,startPos)\r\n\tOS.sleep(0.1)\r\n assert(startPos, 'decode_scanString(..) called without start position')\r\n local startChar = string.sub(s,startPos,startPos)\r\n -- START SoniEx2\r\n -- PS: I don't think single quotes are valid JSON\r\n assert(startChar == [[\"]] or startChar == [[']],'decode_scanString called for a non-string')\r\n --assert(startPos, \"String decoding failed: missing closing \" .. startChar .. \" for string at position \" .. oldStart)\r\n local t = {}\r\n local i,j = startPos,startPos\r\n while string.find(s, startChar, j+1) ~= j+1 do\r\n local oldj = j\r\n i,j = string.find(s, \"\\\\.\", j+1)\r\n local x,y = string.find(s, startChar, oldj+1)\r\n if not i or x < i then\r\n i,j = x,y-1\r\n end\r\n table.insert(t, string.sub(s, oldj+1, i-1))\r\n if string.sub(s, i, j) == \"\\\\u\" then\r\n local a = string.sub(s,j+1,j+4)\r\n j = j + 4\r\n local n = tonumber(a, 16)\r\n assert(n, \"String decoding failed: bad Unicode escape \" .. a .. \" at position \" .. i .. \" : \" .. j)\r\n -- math.floor(x\/2^y) == lazy right shift\r\n -- a % 2^b == bitwise_and(a, (2^b)-1)\r\n -- 64 = 2^6\r\n -- 4096 = 2^12 (or 2^6 * 2^6)\r\n local x\r\n if n < 0x80 then\r\n x = string.char(n % 0x80)\r\n elseif n < 0x800 then\r\n -- [110x xxxx] [10xx xxxx]\r\n x = string.char(0xC0 + (math.floor(n\/64) % 0x20), 0x80 + (n % 0x40))\r\n else\r\n -- [1110 xxxx] [10xx xxxx] [10xx xxxx]\r\n x = string.char(0xE0 + (math.floor(n\/4096) % 0x10), 0x80 + (math.floor(n\/64) % 0x40), 0x80 + (n % 0x40))\r\n end\r\n table.insert(t, x)\r\n else\r\n table.insert(t, escapeSequences[string.sub(s, i, j)])\r\n end\r\n end\r\n table.insert(t,string.sub(j, j+1))\r\n assert(string.find(s, startChar, j+1), \"String decoding failed: missing closing \" .. startChar .. \" at position \" .. j .. \"(for string at position \" .. startPos .. \")\")\r\n return table.concat(t,\"\"), j+2\r\n -- END SoniEx2\r\nend\r\n\r\n--- Scans a JSON string skipping all whitespace from the current start position.\r\n-- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.\r\n-- @param s The string being scanned\r\n-- @param startPos The starting position where we should begin removing whitespace.\r\n-- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string\r\n-- was reached.\r\nfunction decode_scanWhitespace(s,startPos)\r\n local whitespace=\" \\n\\r\\t\"\r\n local stringLen = string.len(s)\r\n while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do\r\n startPos = startPos + 1\r\n end\r\n return startPos\r\nend\r\n\r\n--- Encodes a string to be JSON-compatible.\r\n-- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)\r\n-- @param s The string to return as a JSON encoded (i.e. backquoted string)\r\n-- @return The string appropriately escaped.\r\n\r\nlocal escapeList = {\r\n ['\"'] = '\\\\\"',\r\n ['\\\\'] = '\\\\\\\\',\r\n ['\/'] = '\\\\\/', \r\n ['\\b'] = '\\\\b',\r\n ['\\f'] = '\\\\f',\r\n ['\\n'] = '\\\\n',\r\n ['\\r'] = '\\\\r',\r\n ['\\t'] = '\\\\t'\r\n}\r\n\r\nfunction json_private.encodeString(s)\r\n local s = tostring(s)\r\n return s:gsub(\".\", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat\r\nend\r\n\r\n-- Determines whether the given Lua type is an array or a table \/ dictionary.\r\n-- We consider any table an array if it has indexes 1..n for its n items, and no\r\n-- other data in the table.\r\n-- I think this method is currently a little 'flaky', but can't think of a good way around it yet...\r\n-- @param t The table to evaluate as an array\r\n-- @return boolean, number True if the table can be represented as an array, false otherwise. If true,\r\n-- the second returned value is the maximum\r\n-- number of indexed elements in the array. \r\nfunction isArray(t)\r\n -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable \r\n -- (with the possible exception of 'n')\r\n if (t == json.EMPTY_ARRAY) then return true, 0 end\r\n if (t == json.EMPTY_OBJECT) then return false end\r\n \r\n local maxIndex = 0\r\n for k,v in pairs(t) do\r\n if (type(k)=='number' and math.floor(k)==k and 1<=k) then\t-- k,v is an indexed pair\r\n if (not isEncodable(v)) then return false end\t-- All array elements must be encodable\r\n maxIndex = math.max(maxIndex,k)\r\n else\r\n if (k=='n') then\r\n if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements\r\n else -- Else of (k=='n')\r\n if isEncodable(v) then return false end\r\n end -- End of (k~='n')\r\n end -- End of k,v not an indexed pair\r\n end -- End of loop across all pairs\r\n return true, maxIndex\r\nend\r\n\r\n--- Determines whether the given Lua object \/ table \/ variable can be JSON encoded. The only\r\n-- types that are JSON encodable are: string, boolean, number, nil, table and json.null.\r\n-- In this implementation, all other types are ignored.\r\n-- @param o The object to examine.\r\n-- @return boolean True if the object should be JSON encoded, false if it should be ignored.\r\nfunction isEncodable(o)\r\n local t = type(o)\r\n return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or\r\n (t=='function' and o==json.null) \r\nend\r\n\r\nreturn json","\/modules\/Enum":"local Enum = {}\r\n\r\nEnum.Header = {\r\n SHUTDOWN = \"SHDN\",\r\n FETCHGATEREGISTRY = \"FGR\",\r\n REGISTERGATE = \"RGGT\",\r\n UNREGISTERGATE = \"URGT\",\r\n GATEREGISTRYBROADCAST = \"GTRB\",\r\n SERVERPING = \"SVPG\",\r\n NOTIFICATION = \"NOTF\",\r\n KEEPALIVE = \"KEAL\",\r\n RUNCOMMAND = \"RNCD\",\r\n\tCOMMANDRESPONSE = \"CDRES\",\r\n FILETRANSFERDATA = \"FTFD\",\r\n FILETRANSFERCOMPLETE = \"FTFC\",\r\n\r\n}\r\n\r\nEnum.Header.Gate = {\r\n GATEDIALLINGOUT = \"GDO\",\r\n GATEDIALLINGIN = \"GDI\",\r\n GATEOPENING = \"GTO\",\r\n GATECLOSING = \"GTC\",\r\n GATECONNECTED = \"GCN\",\r\n DIALGATE = \"DG\",\r\n CLOSEGATE = \"CG\",\r\n}\r\n\r\nEnum.Port = {}\r\n\r\nEnum.Port.General = 6000\r\nEnum.Port.Command = 5000\r\nEnum.Port.CommandResponse = 50001\r\nEnum.Port.FTP = 5002\r\nEnum.Port.Keepalive = 5003\r\nEnum.Port.Stargate = 5006\r\nEnum.Port.StargateResponse = 5007\r\nEnum.Port.Notifications = 5008\r\n\r\nEnum.ResType = {}\r\nEnum.ResType.ACK = \"ack\"\r\nEnum.ResType.KEEPALIVE = \"kpal\"\r\nEnum.ResType.FLUSH = \"flsh\"\r\nEnum.ResType.SUCCESS = \"scss\"\r\nEnum.ResType.FAILURE = \"flur\"\r\nEnum.ResType.BUSY = \"bsy\"\r\n\r\n-------------------------------------------------------------------------------\r\n\r\nEnum.Side = {\r\n [0] = \"bottom\",\r\n [1] = \"top\",\r\n [2] = \"back\",\r\n [3] = \"front\",\r\n [4] = \"right\",\r\n [5] = \"left\",\r\n [6] = \"unknown\",\r\n\r\n bottom = 0,\r\n top = 1,\r\n back = 2,\r\n front = 3,\r\n right = 4,\r\n left = 5,\r\n unknown = 6,\r\n\r\n down = 0,\r\n up = 1,\r\n north = 2,\r\n south = 3,\r\n west = 4,\r\n east = 5,\r\n\r\n negy = 0,\r\n posy = 1,\r\n negz = 2,\r\n posz = 3,\r\n negx = 4,\r\n posx = 5,\r\n\r\n forward = 3\r\n}\r\n\r\nlocal sidesMetatable = getmetatable(Enum.Side) or {}\r\n\r\n-- sides[0..5] are mapped to itertable[1..6].\r\nlocal sidesItertable = {\r\n Enum.Side[0],\r\n Enum.Side[1],\r\n Enum.Side[2],\r\n Enum.Side[3],\r\n Enum.Side[4],\r\n Enum.Side[5]\r\n}\r\n\r\n-- Future-proofing against the possible introduction of additional\r\n-- logical sides (e.g. [7] = \"all\", [8] = \"none\", etc.).\r\nfunction sidesMetatable.__len(sides)\r\n return #sidesItertable\r\nend\r\n\r\n-- Allow `sides` to be iterated over like a normal (1-based) array.\r\nfunction sidesMetatable.__ipairs(sides)\r\n return ipairs(sidesItertable)\r\nend\r\n\r\nsetmetatable(Enum.Side, sidesMetatable)\r\n\r\n-------------------------------------------------------------------------------\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Enum\r\n","\/modules\/Formatters":"local Formatters = {}\r\n\r\nFormatters.formatError = function(str)\r\n\treturn \"&#fFF0000&#\"..str..\"&#fFFFFFF&#\"\r\nend\r\n\r\nFormatters.formatSuccess = function(str)\r\n\treturn \"&#f00FF00&#\"..str..\"&#fFFFFFF&#\"\r\nend\r\n\r\nFormatters.formatNotification = function(str)\r\n\treturn \"&#fFFFF00&#\"..str..\"&#fFFFFFF&#\"\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Formatters","\/modules\/testModule":"local module = {}\r\nmodule.stuff = \"things\"\r\n\r\n\r\nreturn module","\/modules\/Shell":"Shell = {}\r\n\r\nShell.ShellBacklog = {{Type = \"print\", Text = formatLoadingHeader(\"Loading complete\")}} -- {Type = \"print\", Text = \" \"}\r\n\r\nShell.promptOpen = false\r\n\r\nShell.prompt = \">>> \"\r\nShell.history = {}\r\n\r\nShell.networkCommandBuffer = {}\r\n\r\nShell.backlogDebounce = false\r\n\r\nShell.print = function(str)\r\n\ttable.insert(Shell.ShellBacklog, {Type = \"print\", Text = str})\r\nend\r\n\r\nShell.printPaged = function(str)\r\n\ttable.insert(Shell.ShellBacklog, {Type = \"printPaged\", Text = str})\r\nend\r\n\r\nShell.stepInterval = 0.05\r\nShell.step = function()\r\n\tif (#Shell.ShellBacklog > 0) and (not Shell.promptOpen) then\r\n\t\tShell.backlogDebounce = true\r\n\t\trepeat\r\n\t\t\tlocal p = Shell.ShellBacklog[1]\r\n\t\t\tif (p.Type == \"print\") then\r\n\t\t\t\tprint(p.Text)\r\n\t\t\telseif (p.Type == \"printPaged\") then\r\n\t\t\t\tprintPaged(p.Text)\r\n\t\t\tend\r\n\t\t\ttable.remove(Shell.ShellBacklog, 1)\r\n\t\tuntil (#Shell.ShellBacklog == 0) or (Shell.promptOpen)\r\n\t\tShell.backlogDebounce = false\r\n\tend\r\nend\r\n\r\nShell.stepNetCmds = function()\r\n\tfor i,p in pairs(Shell.networkCommandBuffer) do\r\n\t\tp.timeout = p.timeout - 2\r\n\t\tif (p.timeout <= 0) then\r\n\t\t\tif (p.ack) then\r\n\t\t\t\tShell.print(Formatters.formatError(\"Command '\"..p.cmd..\"' to \"..p.receiver..\" timed out\"))\r\n\t\t\telse\r\n\t\t\t\tShell.print(Formatters.formatError(\"Command '\"..p.cmd..\"' to \"..p.receiver..\" was not acknowledged\"))\r\n\t\t\tend\r\n\t\t\tShell.networkCommandBuffer[i] = nil\r\n\t\tend\r\n\t\tif (p.done) then Shell.networkCommandBuffer[i] = nil end\r\n\tend\r\nend\r\n\r\nShell.init = function()\r\n\tevent.listen(\"key_down\", Shell.keyDownEventListener)\r\n\tnetwork.registerNetworkListener(Shell.networkCommandResponseListener, \"CommandResponseListener\")\r\n\tevent.timer(2, Shell.stepNetCmds, math.huge)\r\nend\r\n\r\nShell.keyDownEventListener = function(event, address, key, code, plr)\r\n\tif (Shell.promptOpen) then return end\r\n\tShell.promptOpen = true\r\n\tprints(\"\\n&#f32CD32&#Local&#fFFFFFF&#\"..Shell.prompt..\"&#fADD8E6&#\")\r\n\tlocal strIn = term.read(Shell.history):gsub(\"\\n\", \"\")\r\n\tprints(\"&#fFFFFFF&#\")\r\n\tif (strIn == \"\") or (strIn == \" \") then Shell.promptOpen = false return end\r\n\tlocal strTbl = text.split(strIn, \" \")\r\n\tif (not strTbl) then Shell.promptOpen = false return end\r\n\tif (#strTbl < 1) then Shell.promptOpen = false return end\r\n\tif (Shell.networkCommand(strTbl)) then Shell.promptOpen = false return end\r\n\tlocal startText = strTbl[1]\r\n\ttable.remove(strTbl, 1)\r\n\tlocal success, message = pcall(function() Commands.executeCommand(startText, nil, table.unpack(strTbl)) end)\r\n\tif (not success) then print(message) end\r\n\tShell.promptOpen = false\r\nend\r\n\r\nShell.networkCommand = function(tArgs)\r\n\tif (not string.find(tArgs[1], \":\")) then return false end\r\n\tlocal arg1 = text.split(tArgs[1], \":\")\r\n\ttable.remove(tArgs, 1)\r\n\tif (#arg1 ~= 2) then return false end\r\n\tlocal devName = arg1[1]\r\n\tlocal devCmd = arg1[2]\r\n\tif (devName == \"\") or (devName == \" \") or (devCmd == \"\") or (devCmd == \" \") then return false end\r\n\tlocal id = OS.uuid()\r\n\tShell.networkCommandBuffer[id] = {\r\n\t\tid = id,\r\n\t\tcmd = devCmd,\r\n\t\treceiver = devName,\r\n\t\ttimeout = 10,\r\n\t\tack = false,\r\n\t\tdone = false\r\n\t}\r\n\tlocal packet = {Header = Enum.Header.RUNCOMMAND, Receiver = devName, CommandStr = Shell.appendCmd(devCmd, tArgs), id = id}\r\n\tnetwork.sendPacket(Enum.Port.Command, packet, false)\r\n\treturn true\r\nend\r\n\r\nShell.networkCommandResponseListener = function(_, localNetworkCard, remoteAddress, port, distance, packet)\r\n\tif (port ~= 0) and (port ~= Enum.Port.CommandResponse) and (port ~= Enum.Port.General) then return end\r\n\tif (packet.Header ~= Enum.Header.COMMANDRESPONSE) then return end\r\n\tlocal resType = packet.resType\r\n\tlocal id = packet.id\r\n\tlocal bufferEntry = Shell.networkCommandBuffer[id]\r\n\tif (not bufferEntry) then return end\r\n\tif (resType == Enum.ResType.ACK) then\r\n\t\tShell.print(Formatters.formatNotification(bufferEntry.receiver..\" acknowledged reception of command\"))\r\n\t\tbufferEntry.timeout = 10\r\n\t\tbufferEntry.ack = true\r\n\telseif (resType == Enum.ResType.KEEPALIVE) then\r\n\t\tbufferEntry.timeout = tonumber(packet.keepTime) or 10\r\n\telseif (resType == Enum.ResType.FLUSH) then\r\n\t\tif (packet.flushData) then\r\n\t\t\tShell.handleResponse(packet.flushData)\r\n\t\tend\r\n\t\tif (bufferEntry.timeout < 10) then bufferEntry.timeout = 10 end\r\n\telseif (resType == Enum.ResType.SUCCESS) then\r\n\t\tShell.print(Formatters.formatSuccess(\"Command '\"..bufferEntry.cmd..\"' to \"..bufferEntry.receiver..\" completed\"))\r\n\t\tbufferEntry.done = true\r\n\telseif (resType == Enum.ResType.FAILURE) then\r\n\t\tShell.print(Formatters.formatError(\"Command '\"..bufferEntry.cmd..\"' to \"..bufferEntry.receiver..\" failed\"))\r\n\t\tbufferEntry.done = true\r\n\telseif (resType == Enum.ResType.BUSY) then\r\n\t\tShell.print(Formatters.formatError(bufferEntry.receiver..\" is busy\"))\r\n\t\tbufferEntry.done = true\r\n\tend\r\nend\r\n\r\nShell.handleResponse = function(data)\r\n\tfor i=1,#data do\r\n\t\tif (data[i].Type ~= nil) then\r\n\t\t\tif (data[i].Type == \"print\") then\r\n\t\t\t\tShell.print(data[i].text)\r\n\t\t\telseif (data[i].Type == \"printPaged\") then\r\n\t\t\t\tShell.printPaged(data[i].text)\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\nend\r\n\r\nShell.appendCmd = function(name, tbl)\r\n\tlocal str = name..\" \"\r\n\tfor _,s in pairs(tbl) do\r\n\t\tstr = str..s..\" \"\r\n\tend\r\n\treturn str\r\nend\r\n\r\nreturn Shell","\/modules\/serialization":"local serialization = {}\r\n\r\n-- delay loaded tables fail to deserialize cross [C] boundaries (such as when having to read files that cause yields)\r\nlocal local_pairs = function(tbl)\r\n local mt = getmetatable(tbl)\r\n return (mt and mt.__pairs or pairs)(tbl)\r\nend\r\n\r\n-- Important: pretty formatting will allow presenting non-serializable values\r\n-- but may generate output that cannot be unserialized back.\r\nfunction serialization.serialize(value, pretty)\r\n local kw = {[\"and\"]=true, [\"break\"]=true, [\"do\"]=true, [\"else\"]=true,\r\n [\"elseif\"]=true, [\"end\"]=true, [\"false\"]=true, [\"for\"]=true,\r\n [\"function\"]=true, [\"goto\"]=true, [\"if\"]=true, [\"in\"]=true,\r\n [\"local\"]=true, [\"nil\"]=true, [\"not\"]=true, [\"or\"]=true,\r\n [\"repeat\"]=true, [\"return\"]=true, [\"then\"]=true, [\"true\"]=true,\r\n [\"until\"]=true, [\"while\"]=true}\r\n local id = \"^[%a_][%w_]*$\"\r\n local ts = {}\r\n local function s(v, l)\r\n local t = type(v)\r\n if t == \"nil\" then\r\n return \"nil\"\r\n elseif t == \"boolean\" then\r\n return v and \"true\" or \"false\"\r\n elseif t == \"number\" then\r\n if v ~= v then\r\n return \"0\/0\"\r\n elseif v == math.huge then\r\n return \"math.huge\"\r\n elseif v == -math.huge then\r\n return \"-math.huge\"\r\n else\r\n return tostring(v)\r\n end\r\n elseif t == \"string\" then\r\n return string.format(\"%q\", v):gsub(\"\\\\\\n\",\"\\\\n\")\r\n elseif t == \"table\" and pretty and getmetatable(v) and getmetatable(v).__tostring then\r\n return tostring(v)\r\n elseif t == \"table\" then\r\n if ts[v] then\r\n if pretty then\r\n return \"recursion\"\r\n else\r\n error(\"tables with cycles are not supported\")\r\n end\r\n end\r\n ts[v] = true\r\n local i, r = 1, nil\r\n local f\r\n if pretty then\r\n local ks, sks, oks = {}, {}, {}\r\n for k in local_pairs(v) do\r\n if type(k) == \"number\" then\r\n table.insert(ks, k)\r\n elseif type(k) == \"string\" then\r\n table.insert(sks, k)\r\n else\r\n table.insert(oks, k)\r\n end\r\n end\r\n table.sort(ks)\r\n table.sort(sks)\r\n for _, k in ipairs(sks) do\r\n table.insert(ks, k)\r\n end\r\n for _, k in ipairs(oks) do\r\n table.insert(ks, k)\r\n end\r\n local n = 0\r\n f = table.pack(function()\r\n n = n + 1\r\n local k = ks[n]\r\n if k ~= nil then\r\n return k, v[k]\r\n else\r\n return nil\r\n end\r\n end)\r\n else\r\n f = table.pack(local_pairs(v))\r\n end\r\n for k, v in table.unpack(f) do\r\n if r then\r\n r = r .. \",\" .. (pretty and (\"\\n\" .. string.rep(\" \", l)) or \"\")\r\n else\r\n r = \"{\"\r\n end\r\n local tk = type(k)\r\n if tk == \"number\" and k == i then\r\n i = i + 1\r\n r = r .. s(v, l + 1)\r\n else\r\n if tk == \"string\" and not kw[k] and string.match(k, id) then\r\n r = r .. k\r\n else\r\n r = r .. \"[\" .. s(k, l + 1) .. \"]\"\r\n end\r\n r = r .. \"=\" .. s(v, l + 1)\r\n end\r\n end\r\n ts[v] = nil -- allow writing same table more than once\r\n return (r or \"{\") .. \"}\"\r\n else\r\n if pretty then\r\n return tostring(v)\r\n else\r\n error(\"unsupported type: \" .. t)\r\n end\r\n end\r\n end\r\n local result = s(value, 1)\r\n local limit = type(pretty) == \"number\" and pretty or 10\r\n if pretty then\r\n local truncate = 0\r\n while limit > 0 and truncate do\r\n truncate = string.find(result, \"\\n\", truncate + 1, true)\r\n limit = limit - 1\r\n end\r\n if truncate then\r\n return result:sub(1, truncate) .. \"...\"\r\n end\r\n end\r\n return result\r\nend\r\n\r\nfunction serialization.unserialize(data)\r\n checkArg(1, data, \"string\")\r\n local result, reason = load(\"return \" .. data, \"=data\", _, {math={huge=math.huge}})\r\n if not result then\r\n return nil, reason\r\n end\r\n local ok, output = pcall(result)\r\n if not ok then\r\n return nil, output\r\n end\r\n return output\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn serialization","\/modules\/Device":"local Device = {}\r\nDevice.driverList = {\r\n\tDefault = {Name = \"Default\", desc = \"Default, no special function\"};\r\n\tServer = {Name = \"Server\", desc = \"Central control server for networked devices\"};\r\n\tTablet = {Name = \"Tablet\", desc = \"Remote control terminal\", file = \"Tablet\"};\r\n\tFusion_Reactor = {Name = \"Fusion_Reactor\", desc = \"Used to control the Mekanism Fusion Reactor\"};\r\n\tRedstone = {Name = \"Redstone\", desc = \"Used to control redstone\"};\r\n}\r\n\r\nDevice.miniAppList = {\r\n\tLRelay = {Name = \"LRelay\", desc = \"Relay program for linked cards\", file = \"LinkedRelay\"};\r\n\tGCont = {Name = \"GCont\", desc = \"Used to control Stargates which are not connected to a full StattenOS network\", file = \"GateController\"};\r\n}\r\n\r\nDevice.currentConfig = {\r\n\tName = computer.address():sub(1,8);\r\n\tDriver = \"Default\";\r\n}\r\n\r\nDevice.Driver = nil\r\nDevice.updateReceived = false\r\nDevice.updateFiles = {}\r\nDevice.updateDirectories = {}\r\nDevice.okToUpdate = false\r\nDevice.updating = false\r\n\r\nDevice.updatePackage = nil\r\n\r\nDevice.loadConfig = function()\r\n\tlocal str = Packager.getFileString(\"\/config\")\r\n\tif (not str) then print(\"'\/config' does not exist, creating new configuration file\") return end\r\n\tDevice.currentConfig = serialization.unserialize(str) or Device.currentConfig\r\n\treturn true\r\nend\r\n\r\nDevice.saveConfig = function()\r\n\tlocal str = serialization.serialize(Device.currentConfig)\r\n\tlocal handle, reason = filesystem.open(\"\/config\", \"w\")\r\n\tif (not handle) then\r\n\t\tprint(\"Unable to open file \"..\"\/config\"..\"(\"..reason..\")\")\r\n\t\treturn false\r\n\tend\r\n\tfilesystem.write(handle, str)\r\n\tfilesystem.close(handle)\r\n\treturn true\r\nend\r\n\r\n\r\nDevice.commandListener = function(_, localNetworkCard, remoteAddress, port, distance, packet)\r\n\tif (port ~= 0) and (port ~= Enum.Port.Command) and (port ~= Enum.Port.General) then return end\r\n\tif (packet.Header == Enum.Header.RUNCOMMAND) then\r\n\t\tif (Commands.busy) then Device.commandBusyResponse(packet) return end\r\n\t\tlocal cmd = tostring(packet.CommandStr) or \"\"\r\n\t\tShell.print(\"\\n&#f32CD32&#\"..packet.Sender..\"&#fFFFFFF&#\"..Shell.prompt..\"&#fADD8E6&#\"..packet.CommandStr..\"&#fFFFFFF&#\")\r\n\t\tOS.sleep(0.1)\r\n\t\tlocal strTbl = text.split(cmd, \" \")\r\n\t\tif (not strTbl) then Device.commandFailResponse(packet) return end\r\n\t\tif (#strTbl < 1) then Device.commandFailResponse(packet) return end\r\n\t\tlocal startText = strTbl[1]\r\n\t\ttable.remove(strTbl, 1)\r\n\t\tlocal newStrTbl = {}\r\n\t\tfor i,p in pairs(strTbl) do\r\n\t\t\tif (p ~= \"\") and (p ~= \" \") and (p ~= nil) then\r\n\t\t\t\ttable.insert(newStrTbl, p)\r\n\t\t\tend\r\n\t\tend\r\n\t\tlocal success, message = pcall(function() Commands.executeCommand(startText, packet, table.unpack(newStrTbl)) end)\r\n\t\tif (not success) then print(message) end\r\n\tend\r\nend\r\n\r\nDevice.commandFailResponse = function(packet)\r\n\tlocal response = newResponse(packet)\r\n\tresponse:sendAck()\r\n\tresponse:sendFailure()\r\nend\r\n\r\nDevice.commandBusyResponse = function(packet)\r\n\tlocal response = newResponse(packet)\r\n\tresponse:sendAck()\r\n\tresponse:sendBusy()\r\nend\r\n\r\nDevice.updateListener = function(_, FileName, FilePath) -- FTP event Listener\r\n\tif (FileName == \"UpdatePackage\") then\r\n\t\tShell.print(\"Received update package, run 'reboot' to install update and reboot\")\r\n\t\tDevice.updatePackage = FilePath\r\n\tend\r\nend\r\n\r\nDevice.init = function()\r\n\tDevice.loadConfig()\r\n\tprint(\"Loading Device Driver '\"..Device.currentConfig.Driver..\"'\")\r\n\tlocal driverPath = \"\/drivers\/\"..Device.currentConfig.Driver\r\n\tif (filesystem.exists(driverPath)) then\r\n\t\tDevice.Driver = dofile(driverPath)\r\n\t\tif (Device.Driver) then\r\n\t\t\tDevice.Driver.load(Device.currentConfig)\r\n\t\t\tDevice.Driver.init()\r\n\t\t\tDevice.Driver.registerCommands()\r\n\t\t\tDevice.saveConfig()\r\n\t\telse\r\n\t\t\tnetwork.registerPingListener()\r\n\t\tend\r\n\telse\r\n\t\tnetwork.registerPingListener()\r\n\tend\r\n\tprint(\"Device Name: \"..Device.currentConfig.Name)\r\n\tnetwork.registerNetworkListener(Device.commandListener)\r\n\tnetwork.ftp.registerFtpListener(Device.updateListener)\r\n\t-- set label\r\n\tlocal dProxy = fs.drive.letterToProxy(initDrive)\r\n\tdProxy.setLabel(Device.currentConfig.Name)\r\n\t-- send notification to server\r\n\tnetwork.sendKeepalivePacket()\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Device\r\n","\/modules\/Packager":"local Packager = {}\r\n\r\nPackager.devKey = \"b135baaf9837ed1ec7bcb629eaf1adbc\"\r\nPackager.loggedUsr = \"elijahlorden\"\r\nPackager.loggedPss = \"elijah24680\"\r\n\r\nPackager.installProgPart1 = [[\r\ncomputer = require(\"computer\")\r\nevent = require(\"event\")\r\nfunction JSONLib()\r\n\r\n]]\r\n\r\nPackager.installProgPart2 = [[\r\n\r\nend\r\nOS = {}\r\nfunction OS.sleep(timeout)\r\n\tcheckArg(1, timeout, \"number\", \"nil\")\r\n\tlocal deadline = computer.uptime() + (timeout or 0)\r\n\trepeat\r\n\t\tevent.pull(deadline - computer.uptime())\r\n\tuntil computer.uptime() >= deadline\r\nend\r\n\r\nfunction installOS(path, packagedOS)\r\n\tfor i,p in pairs(packagedOS.Directories) do\r\n\t\tfs.makeDirectory(p)\r\n\tend\r\n\tfor i,p in pairs(packagedOS) do\r\n\t\tif (i ~= \"Directories\") then\r\n\t\t\tfor fn,f in pairs(p) do -- path,data\r\n\t\t\t\tprint(\"Installing \"..fn)\r\n\t\t\t\tif (type(f):lower() == \"string\") then\r\n\t\t\t\t\tlocal file = io.open(fn, \"w\")\r\n\t\t\t\t\tfile:write(f)\r\n\t\t\t\t\tfile:close()\r\n\t\t\t\tend\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\n\t\r\n\t\r\n\t\r\nend\r\n\r\nfilesystem = require(\"filesystem\")\r\nio = require(\"io\")\r\n\r\nfunction installOS(packagedOS)\r\n\tfor i,p in pairs(packagedOS.Directories) do\r\n\t\tfilesystem.makeDirectory(p)\r\n\tend\r\n\tfor i,p in pairs(packagedOS) do\r\n\t\tif (i ~= \"Directories\") then\r\n\t\t\tfor fn,f in pairs(p) do -- path,data\r\n\t\t\t\tprint(\"Installing \"..fn)\r\n\t\t\t\tif (type(f):lower() == \"string\") then\r\n\t\t\t\t\tlocal file, reason = io.open(\"\/\"..fn, \"w\")\r\n\t\t\t\t\tif (not file) then print(reason) end\r\n\t\t\t\t\tfile:write(f)\r\n\t\t\t\t\tfile:close()\r\n\t\t\t\tend\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\nend\r\n\r\nfunction wipe()\r\n\tfor f in filesystem.list(\"\/\") do\r\n\t\tif (f:sub(f:len(), f:len()) == \"\/\") then f = f:sub(0,f:len()-1) end\r\n\t\tfilesystem.remove(f)\r\n\t\tprint(\"Deleting \"..f)\r\n\tend\r\nend\r\n\r\nprint(\"StattenOS Installer\")\r\nlocal JSON = JSONLib()\r\nlocal file = io.open(\"\/InstallData\")\r\nlocal InstallData = file:read(\"*a\")\r\nfile:close()\r\nprint(\"InstallData read into memory, decoding...\")\r\nlocal OSTable = JSON.decode(InstallData)\r\nprint(\"Decoded, procedding with install\")\r\nprint(\"wiping drive from root directory\")\r\nwipe()\r\nprint(\"wipe, complete, installing...\")\r\ninstallOS(OSTable)\r\nprint(\"Install complete.\")\r\n]]\r\n\r\n\r\nPackager.assembleInstallFiles = function()\r\n\tlocal OSproxy = fs.drive.letterToProxy(\"A\")\r\n\tlocal str = Packager.installProgPart1\r\n\tlocal packagedOS = Packager.packageIntoTable()\r\n\tlocal serializedOS = JSON.encode(packagedOS)\r\n\tlocal JSONModule = Packager.getFileString(\"\/modules\/JSON\")\r\n\tstr = str..JSONModule\r\n\tstr = str..Packager.installProgPart2\r\n\treturn str, serializedOS\r\nend\r\n\r\nPackager.packageIntoTable = function()\r\n\tlocal tbl = {Directories = {}}\r\n\tprint(\"Packaging OS...\")\r\n\tPackager.processFolder(\"\/\", tbl)\r\n\tprint(\"OS packaged\")\r\n\treturn tbl\r\nend\r\n\r\nPackager.processFolder = function(path, tbl)\r\n\ttable.insert(tbl.Directories, path)\r\n\tlocal folderItems = {}\r\n\tlocal list = filesystem.list(path)\r\n\tfor f in list do\r\n\t\tOS.sleep(0.05)\r\n\t\tif (filesystem.isDirectory(f)) and (not f:find(\"tmp\")) then\r\n\t\t\tPackager.processFolder(path..f, tbl)\r\n\t\telseif (not filesystem.isDirectory(f)) then\r\n\t\t\tif (f ~= \"config\") then\r\n\t\t\t\tprint(\"Packaging \"..path..f)\r\n\t\t\t\tlocal str = Packager.getFileString(path..f)\r\n\t\t\t\tfolderItems[path..f] = str\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\n\ttable.insert(tbl, folderItems)\r\nend\r\n\r\nPackager.getFileString = function(path, proxy)\r\n\tif (not proxy) then proxy = filesystem end\r\n\tlocal handle, reason = proxy.open(path)\r\n\tif (not handle) then\r\n\t\tprint(\"Unable to read file \"..path..\"(\"..reason..\")\")\r\n\t\treturn\r\n\tend\r\n\tlocal buffer = \"\"\r\n\trepeat\r\n\tlocal data, reason = proxy.read(handle, math.huge)\r\n\tif (not data) and (reason) then\r\n\t\tprint(\"Unable to read file \"..path..\"(\"..reason..\")\")\r\n\t\treturn\r\n end\r\n\tbuffer = buffer..(data or \"\")\r\n\tuntil not data\r\n\tproxy.close(handle)\r\n\treturn buffer\r\nend\r\n\r\nPackager.joinList = function(list)\r\n\tlocal s = \"\"\r\n\tfor _,p in pairs(list) do\r\n\t\ts = s..p\r\n\tend\r\n\treturn s\r\nend\r\n\r\nPackager.request = function(address, args)\r\n\tif not component.isAvailable(\"internet\") then\r\n\t\tprint(\"No internet card, unable to send HTTP request\")\r\n\t\treturn\r\n\tend\r\n\tlocal internet = component.internet\r\n\tlocal result, request = pcall(internet.request, address, args)\r\n\t--print(result)\r\n\tif (result) then\r\n\t\tlocal buffer = \"\"\r\n\t\trepeat\r\n\t\t\tlocal data, reason = request.read()\r\n\t\t\tif (not data) and (reason) then error(reason) end\r\n\t\t\tbuffer = buffer..(data or \"\")\r\n\t\tuntil not data\r\n\t\trequest.close()\r\n\t\tif (string.match(buffer, \"^Bad API request, \")) then\r\n\t\t\tprint(\"HTTP Request Failed: \"..buffer)\r\n\t\t\treturn\r\n\t\tend\r\n\t\treturn buffer\r\n\telse\r\n\t\tprint(\"HTTP Request Failed\")\r\n\tend\r\nend\r\n\r\nPackager.writeFile = function(proxy, path, str)\r\n\tlocal handle = proxy.open(path, \"w\")\r\n\tif (not handle) then print(\"Unable to create file \"..path) end\r\n\tproxy.write(handle, str)\r\nend\r\n\r\nPackager.wipeDriveForOSInstall = function(proxy, path)\r\n\tfor _,f in pairs(proxy.list(path)) do\r\n\t\tif (f ~= \"config\") then\r\n\t\t\tproxy.remove(path..f)\r\n\t\t\tprint(\"Deleting \"..f)\r\n\t\tend\r\n\tend\r\nend\r\n\r\nPackager.wipeDriveForOSInstall2 = function(proxy, path)\r\n\tfor _,f in pairs(proxy.list(path)) do\r\n\t\tif (f ~= \"config\") then\r\n\t\t\tproxy.remove(path..f)\r\n\t\t\tShell.print(\"Deleting \"..f)\r\n\t\tend\r\n\tend\r\nend\r\n\r\nPackager.installToDrive = function(driveLetter)\r\n\tlocal proxy = fs.drive.letterToProxy(driveLetter)\r\n\tif (not proxy) then print(\"Drive does not exist\") return false end\r\n\tprint(\"Wiping drive \"..driveLetter)\r\n\tPackager.wipeDriveForOSInstall(proxy, \"\/\")\r\n\tlocal packagedOS = Packager.packageIntoTable()\r\n\tfor i,p in pairs(packagedOS.Directories) do\r\n\t\tproxy.makeDirectory(p)\r\n\tend\r\n\tOS.sleep(0.5)\r\n\tfor i,p in pairs(packagedOS) do\r\n\t\tif (i ~= \"Directories\") then\r\n\t\t\tfor fn,f in pairs(p) do\r\n\t\t\t\tprint(\"Installing \"..fn)\r\n\t\t\t\tif (type(f):lower() == \"string\") then\r\n\t\t\t\t\tPackager.writeFile(proxy, fn, f)\r\n\t\t\t\t\tOS.sleep(0.1)\r\n\t\t\t\tend\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\n\treturn true\r\nend\r\n\r\nPackager.copyOSFileToDrive = function(driveProxy, filePath, newName)\r\n\tlocal inStr = Packager.getFileString(filePath)\r\n\tlocal handle = driveProxy.open(\"\/\"..newName, \"w\")\r\n\tdriveProxy.write(handle, inStr)\r\n\tprint(\"copied \"..filePath..\" to \"..newName)\r\nend\r\n\r\nPackager.copyOSFileToDrive2 = function(driveProxy, filePath, newName)\r\n\tlocal inStr = Packager.getFileString(filePath)\r\n\tlocal handle = driveProxy.open(\"\/\"..newName, \"w\")\r\n\tdriveProxy.write(handle, inStr)\r\n\tShell.print(\"copied \"..filePath..\" to \"..newName)\r\nend\r\n\r\nPackager.installMiniAppToDrive = function(drive, appFile)\r\n\tlocal proxy = fs.drive.letterToProxy(drive)\r\n\tif (not proxy) then print(\"Drive does not exist\") return false end\r\n\tprint(\"Wiping drive \"..drive)\r\n\tPackager.wipeDriveForOSInstall(proxy, \"\/\")\r\n\tprint(\"Wiped\")\r\n\tPackager.copyOSFileToDrive(proxy, \"\/init.lua\", \"\/init.lua\")\r\n\tPackager.copyOSFileToDrive(proxy, \"\/CoreLibs.lua\", \"\/CoreLibs.lua\")\r\n\tPackager.copyOSFileToDrive(proxy, \"\/Keyboard.lua\", \"\/Keyboard.lua\")\r\n\tPackager.copyOSFileToDrive(proxy, appFile, \"\/OS.lua\")\r\n\tfor f in filesystem.list(\"\/modules\/\") do\r\n\t\tPackager.copyOSFileToDrive(proxy, \"\/modules\/\"..f, \"\/\"..f)\r\n\tend\r\n\treturn true\r\nend\r\n\r\nPackager.installMiniAppToDriveProxy = function(proxy, appFile)\r\n\tif (not proxy) then Shell.print(\"Drive does not exist\") return false end\r\n\tShell.print(\"Wiping drive\")\r\n\tPackager.wipeDriveForOSInstall2(proxy, \"\/\")\r\n\tShell.print(\"Wiped\")\r\n\tPackager.copyOSFileToDrive(proxy, \"\/init.lua\", \"\/init.lua\")\r\n\tPackager.copyOSFileToDrive(proxy, \"\/CoreLibs.lua\", \"\/CoreLibs.lua\")\r\n\tPackager.copyOSFileToDrive(proxy, \"\/Keyboard.lua\", \"\/Keyboard.lua\")\r\n\tPackager.copyOSFileToDrive(proxy, appFile, \"\/OS.lua\")\r\n\tfor f in filesystem.list(\"\/modules\/\") do\r\n\t\tPackager.copyOSFileToDrive2(proxy, \"\/modules\/\"..f, \"\/\"..f)\r\n\tend\r\n\treturn true\r\nend\r\n\r\nPackager.writeTmpFile = function(name, contents)\r\n\tlocal proxy = fs.proxy(computer.getBootAddress())\r\n\tPackager.writeFile(proxy, \"\/tmp\/\"..name, contents)\r\n\treturn true\r\nend\r\n\r\nPackager.installUpdatePackage = function(packagePath)\r\n\tlocal proxy = fs.drive.letterToProxy(\"A\")\r\n\t----- get package -----\r\n\tlocal inStr = Packager.getFileString(packagePath)\r\n\tif (not inStr) then print(\"Update failed\") return false end\r\n\tlocal packagedOS = JSON.decode(inStr)\r\n\tif (not packagedOS) or (not packagedOS.Directories) then print(\"Update failed\") return false end\r\n\tprint(\"Wiping drive\")\r\n\tPackager.wipeDriveForOSInstall(proxy, \"\/\")\r\n\tfor i,p in pairs(packagedOS.Directories) do\r\n\t\tproxy.makeDirectory(p)\r\n\tend\r\n\tOS.sleep(0.5)\r\n\tfor i,p in pairs(packagedOS) do\r\n\t\tif (i ~= \"Directories\") then\r\n\t\t\tfor fn,f in pairs(p) do\r\n\t\t\t\tprint(\"Installing \"..fn)\r\n\t\t\t\tif (type(f):lower() == \"string\") then\r\n\t\t\t\t\tPackager.writeFile(proxy, fn, f)\r\n\t\t\t\t\tOS.sleep(0.1)\r\n\t\t\t\tend\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\n\treturn true\r\nend\r\n\r\nPackager.installUpdateFromDrive = function(packagePath)\r\n\tif (not packagePath) or (type(packagePath) ~= \"string\") or (#packagePath < 4) then return false end\r\n\tlocal proxy = fs.drive.letterToProxy(packagePath:sub(1,1))\r\n\tlocal aProxy = fs.drive.letterToProxy(\"A\")\r\n\tif (not proxy) then return false end\r\n\tif (packagePath:sub(2,2) == \":\") then --A:\/path\r\n\t\tpackagePath = packagePath:sub(3)\r\n\telse --A\/path\r\n\t\tpackagePath = packagePath:sub(2)\r\n\tend\r\n\t----- get package -----\r\n\tlocal inStr = Packager.getFileString(packagePath, proxy)\r\n\tif (not inStr) then return false end\r\n\tlocal packagedOS = JSON.decode(inStr)\r\n\tif (not packagedOS) or (not packagedOS.Directories) then return false end\r\n\tprint(\"Wiping drive\")\r\n\tPackager.wipeDriveForOSInstall(aProxy, \"\/\")\r\n\tfor i,p in pairs(packagedOS.Directories) do\r\n\t\taProxy.makeDirectory(p)\r\n\tend\r\n\tOS.sleep(0.5)\r\n\tfor i,p in pairs(packagedOS) do\r\n\t\tif (i ~= \"Directories\") then\r\n\t\t\tfor fn,f in pairs(p) do\r\n\t\t\t\tprint(\"Installing \"..fn)\r\n\t\t\t\tif (type(f):lower() == \"string\") then\r\n\t\t\t\t\tPackager.writeFile(aProxy, fn, f)\r\n\t\t\t\t\tOS.sleep(0.1)\r\n\t\t\t\tend\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\n\treturn true\r\nend\r\n\r\nPackager.componentAdded = function(_, address, componentType)\r\n\tif (componentType == \"filesystem\") then\r\n\t\tlocal proxy = component.proxy(address)\r\n\t\tif (not proxy) then return end\r\n\t\tlocal label = proxy.getLabel()\r\n\t\tlocal splitLabel = text.split(label, \":\")\r\n\t\tif (#splitLabel < 2) then return end\r\n\t\tif (splitLabel[1] == \"ma\") then\r\n\t\t\tlocal appName = splitLabel[2]\r\n\t\t\tif (Device.miniAppList[appName] ~= nil) then\r\n\t\t\t\tShell.print(\"Auto-updating miniApp\")\r\n\t\t\t\tPackager.installMiniAppToDriveProxy(proxy, \"\/miniapps\/\"..Device.miniAppList[appName].file)\r\n\t\t\tend\r\n\t\tend\r\n\tend\r\nend\r\n\r\nPackager.init = function()\r\n\tevent.listen(\"component_added\", Packager.componentAdded)\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nreturn Packager"},"4":{"\/OS.lua":"OS = {}\r\nOS.Name = \"StattenOS\"\r\nOS.Version = \"0.0.1\"\r\nOS.modules = {}\r\nOS.allowedRootFiles = {\"drivers\/\", \"miniapps\/\", \"modules\/\", \"tmp\/\", \"config\", \"CoreLibs.lua\", \"init.lua\", \"Keyboard.lua\", \"OS.lua\"}\r\n\r\nOS.chars = \"abcdefghijklmnopqrstuvwxyz0123456789\"\r\n\r\nfunction OS.sleep(timeout)\r\n\tcheckArg(1, timeout, \"number\", \"nil\")\r\n\tlocal deadline = computer.uptime() + (timeout or 0)\r\n\trepeat\r\n\t\tevent.pull(deadline - computer.uptime())\r\n\tuntil computer.uptime() >= deadline\r\nend\r\n\r\nfunction OS.uuid()\r\n\tmath.randomseed(computer.uptime())\r\n\tlocal s = \"\"\r\n\tfor i=1,8 do local n = math.random(1,OS.chars:len()) s = s..(OS.chars:sub(n,n)) end\r\n\ts = s..\"-\"\r\n\tfor i=1,4 do local n = math.random(1,OS.chars:len()) s = s..(OS.chars:sub(n,n)) end\r\n\ts = s..\"-\"\r\n\tfor i=1,4 do local n = math.random(1,OS.chars:len()) s = s..(OS.chars:sub(n,n)) end\r\n\ts = s..\"-\"\r\n\tfor i=1,4 do local n = math.random(1,OS.chars:len()) s = s..(OS.chars:sub(n,n)) end\r\n\ts = s..\"-\"\r\n\tfor i=1,11 do local n = math.random(1,OS.chars:len()) s = s..(OS.chars:sub(n,n)) end\r\n\treturn s\r\nend\r\n\r\nfunction loadfile(file, mode, env)\r\n local handle, reason = filesystem.open(file)\r\n if not handle then\r\n error(reason, 2)\r\n end\r\n local buffer = \"\"\r\n repeat\r\n local data, reason = filesystem.read(handle)\r\n if not data and reason then\r\n error(reason)\r\n end\r\n buffer = buffer .. (data or \"\")\r\n until not data\r\n filesystem.close(handle)\r\n if mode == nil then mode = \"bt\" end\r\n if env == nil then env = _G end\r\n return load(buffer, \"=\" .. file)\r\nend\r\n\r\nfunction dofile(file)\r\n local program, reason = loadfile(file)\r\n if program then\r\n local result = table.pack(pcall(program))\r\n if result[1] then\r\n return table.unpack(result, 2, result.n)\r\n else\r\n error(result[2])\r\n end\r\n else\r\n error(reason)\r\n end\r\nend\r\n\r\n-- core libraries\r\n\r\nevent = event_code()\r\ncomponent_code()\r\ntext = text_code()\r\nfilesystem = fs_code()\r\nfs = filesystem\r\nkeyboard = dofile(\"\/Keyboard.lua\")\r\nterm = terminal_code()\r\n\r\nevent_code, component_code, text_code, fs_code, terminal_code = nil, nil, nil, nil, nil\r\n\r\n-- bind GPU\r\n\r\nif term.isAvailable() then\r\n component.gpu.bind(component.screen.address)\r\n component.gpu.setResolution(component.gpu.getResolution())\r\n component.gpu.setBackground(0x000000)\r\n component.gpu.setForeground(0xFFFFFF)\r\n term.setCursorBlink(false)\r\n term.clear()\r\nend\r\n\r\nprint(\"Starting \"..OS.Name..\" \"..OS.Version)\r\n\r\nfunction kernelError()\r\n\tprintErr(\"\\nPress any key to try again.\")\r\n\tterm.readKey()\r\nend\r\n\r\nlocal function interrupt(data)\r\n\tif data[2] == \"RUN\" then miniOS.runfile(data[3], table.unpack(data[4])) end\r\nend\r\n\r\nlocal function runfile(file, ...)\r\n\tlocal program, reason = loadfile(file)\r\n\tif program then\r\n\t\tlocal result = table.pack(pcall(program, ...))\r\n\t\t\tif result[1] then\r\n\t\t\t\treturn table.unpack(result, 2, result.n)\r\n\t\t\telse\r\n\t\t\t\tif type(result[2]) == \"table\" then if result[2][1] then if result[2][1] == \"INTERRUPT\" then interrupt(result[2]) return end end end\r\n\t\t\t\terror(result[2], 3)\r\n\t\t\tend\r\n\telse\r\n\t\terror(reason, 3)\r\n\tend\r\nend\r\n\r\nfunction newResponse(cPacket)\r\n\tlocal tbl = {}\r\n\tif (cPacket) then\r\n\t\ttbl = { sender = cPacket.Sender, id = cPacket.id}\r\n\tend\r\n\ttbl.contents = {}\r\n\ttbl.done = false\r\n\ttbl.print = function(this, text)\r\n\t\ttable.insert(this.contents, {Type = \"print\", text = text})\r\n\t\tif (this.sender) then\r\n\t\t\tShell.print(text)\r\n\t\telse\r\n\t\t\tprint(text)\r\n\t\tend\r\n\tend\r\n\ttbl.printPaged = function(this, text)\r\n\t\ttable.insert(this.contents, {Type = \"printPaged\", text = text})\r\n\t\tif (this.sender) then\r\n\t\t\tShell.printPaged(text)\r\n\t\telse\r\n\t\t\tprintPaged(text)\r\n\t\tend\r\n\tend\r\n\ttbl.sendAck = function(this)\r\n\t\tif (not this.sender) then return end\r\n\t\tlocal packet = {Header = Enum.Header.COMMANDRESPONSE, Receiver = this.sender, id = this.id, resType = Enum.ResType.ACK}\r\n\t\tnetwork.sendPacket(Enum.Port.CommandResponse, packet, false)\r\n\tend\r\n\ttbl.flush = function(this)\r\n\t\tif (not this.sender) or (#this.contents < 1) then return end\r\n\t\tlocal packet = {Header = Enum.Header.COMMANDRESPONSE, Receiver = this.sender, id = this.id, resType = Enum.ResType.FLUSH, flushData = this.contents}\r\n\t\tnetwork.sendPacket(Enum.Port.CommandResponse, packet, false)\r\n\t\tthis.contents = {}\r\n\tend\r\n\ttbl.sendSuccess = function(this)\r\n\t\tif (not this.sender) or (this.done) then return end\r\n\t\tthis.done = true\r\n\t\tlocal packet = {Header = Enum.Header.COMMANDRESPONSE, Receiver = this.sender, id = this.id, resType = Enum.ResType.SUCCESS}\r\n\t\tnetwork.sendPacket(Enum.Port.CommandResponse, packet, false)\r\n\tend\r\n\ttbl.sendBusy = function(this)\r\n\t\tif (not this.sender) or (this.done) then return end\r\n\t\tthis.done = true\r\n\t\tlocal packet = {Header = Enum.Header.COMMANDRESPONSE, Receiver = this.sender, id = this.id, resType = Enum.ResType.BUSY}\r\n\t\tnetwork.sendPacket(Enum.Port.CommandResponse, packet, false)\r\n\tend\r\n\ttbl.sendFailure = function(this)\r\n\t\tif (not this.sender) or (this.done) then return end\r\n\t\tthis.done = true\r\n\t\tlocal packet = {Header = Enum.Header.COMMANDRESPONSE, Receiver = this.sender, id = this.id, resType = Enum.ResType.FAILURE}\r\n\t\tnetwork.sendPacket(Enum.Port.CommandResponse, packet, false)\r\n\tend\r\n\ttbl.sendKeepalive = function(this, t)\r\n\t\tif (not this.sender) then return end\r\n\t\tlocal packet = {Header = Enum.Header.COMMANDRESPONSE, Receiver = this.sender, id = this.id, resType = Enum.ResType.KEEPALIVE, keepTime = t}\r\n\t\tnetwork.sendPacket(Enum.Port.CommandResponse, packet, false)\r\n\tend\r\n\treturn tbl\r\nend\r\n\r\nfunction mapToKeyPair(tbl)\r\n\tlocal nt = {}\r\n\tlocal n = 1\r\n\tfor i,p in pairs(tbl) do\r\n\t\tnt[n] = p\r\n\t\tn = n + 1\r\n\tend\r\n\treturn nt\r\nend\r\n\r\nformatLoadingHeader = function(str)\r\n\treturn \"&#f32CD32&#== &#fADD8E6&#\"..str..\"&#f32CD32&# ==&#fFFFFFF&#\"\r\nend\r\n\r\nOS.runfile = runfile\r\n\r\nloadModules = function(path)\r\n\tprint(\"Loading modules in \"..path)\r\n\tlocal files = fs.list(path) -- get list of files in the directory 'path'\r\n\tfor f in files do -- use a FOR loop to iterate over the list of files\r\n\t\tprint(\"Loading module \"..path..f)\r\n\t\tretModule = dofile(path..f) -- get the module table that results from executing the file\r\n\t\t_G[f] = retModule -- assign the table to the global namespace\r\n\t\tOS.modules[f] = retModule -- add the module to OS.modules so it can be referenced\r\n\tend\r\nend\r\n\r\nprint()\r\nfilesystem.remove(\"\/tmp\")\r\nfilesystem.makeDirectory(\"\/tmp\")\r\nprint(\"Cleared \/tmp\")\r\n\r\n-- Load modules\r\nprint()\r\nprint(formatLoadingHeader(\"Load Modules\"))\r\nprint()\r\n\r\nloadModules(\"\/modules\/\")\r\n\r\ninitDrive = fs.drive.getcurrent()\r\n\r\nfunction doInit() -- Initalize modules\r\n\tprint()\r\n\tprint(formatLoadingHeader(\"Initalize Modules\"))\r\n\tprint()\r\n\t\r\n\tfor i,p in pairs(OS.modules) do\r\n\t\tif (p.init ~= nil) then\r\n\t\t\tp.init()\r\n\t\tend\r\n\tend\r\n\r\n\tfor i,p in pairs(OS.modules) do\r\n\t\tif (p.step ~= nil) then\r\n\t\t\tevent.timer(p.stepInterval or 1, p.step, math.huge)\r\n\t\tend\r\n\tend\r\n\tprint()\r\nend\r\n\r\nprint()\r\nprint(\"All modules loaded into Memory\")\r\nprint()\r\nprint(\"Memory: \"..tostring(math.floor((computer.totalMemory() - computer.freeMemory())\/1024))..\"KB used \/ \"..tostring(math.floor(computer.totalMemory()\/1024))..\"KB total\")\r\nprint()\r\n\r\n\r\n\r\nOS.memoryMsgStr = function()\r\n\t--return \"Memory: \"..tostring(math.floor((computer.totalMemory() - computer.freeMemory())\/1024))..\"KB used \/ \"..tostring(math.floor(computer.totalMemory()\/1024))..\"KB total\"\r\n\treturn \"Memory: \"..tostring(math.floor((computer.totalMemory() - OS.averageMem())\/1024))..\"KB used \/ \"..tostring(math.floor(computer.totalMemory()\/1024))..\"KB total\"\r\nend\r\n\r\nOS.powerMsgStr = function()\r\n\treturn \"Energy: \"..tostring(math.floor(computer.energy()))..\"\/\"..tostring(math.floor(computer.maxEnergy()))\r\nend\r\n\r\nOS.cleanNils = function(t)\r\n\tlocal ans = {}\r\n\tfor _,v in pairs(t) do\r\n\t\tans[ #ans+1 ] = v\r\n\tend\r\n\treturn ans\r\nend\r\n\r\nOS.memAverages = {}\r\n\r\nOS.averageMem = function()\r\n\tlocal t = 0\r\n\tfor _,n in pairs(OS.memAverages) do\r\n\t\tt = t + n\r\n\tend\r\n\tt = t\/#OS.memAverages\r\n\treturn t\r\nend\r\n\r\nOS.doesTableContainString = function(tbl, str, caseSensitive)\r\n\tif (caseSensitive == nil) then caseSensitive = true end\r\n\tfor i,p in pairs(tbl) do\r\n\t\tif (caseSensitive) then\r\n\t\t\tif (i == str) or (p == str) then return true end\r\n\t\telse\r\n\t\t\tif (i:lower() == str:lower()) or (p:lower() == str:lower()) then return true end\r\n\t\tend\r\n\tend\r\n\treturn false\r\nend\r\n\r\nprint(formatLoadingHeader(\"Cleaning Root Directory\"))\r\nfor f in filesystem.list(\"\/\") do -- remove unwanted files from root\r\n\tif (not OS.doesTableContainString(OS.allowedRootFiles, f, true)) then\r\n\t\tif (f:sub(f:len(), f:len()) == \"\/\") then f = f:sub(0,f:len()-1) end -- remove '\/' postfixed to directories\r\n\t\tfilesystem.remove(f)\r\n\t\tprint(\"Removed \/\"..f)\r\n\tend\r\nend\r\nprint()\r\n\r\ndoInit() -- Initalize modules\r\n\r\nlocal sec = 0\r\nlocal memSec = 0\r\nwhile true do\r\n\tOS.sleep(0.01)\r\n\tsec = sec + 0.01\r\n\tmemSec = memSec + 0.01\r\n\tif (sec > 1) then sec = 0 end\r\n\tif (memSec > 1) then\r\n\t\ttable.insert(OS.memAverages, computer.freeMemory())\r\n\t\tif (#OS.memAverages > 20) then table.remove(OS.memAverages, 1) end\r\n\tend\r\nend\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n","\/CoreLibs.lua":"--[[\r\nCopyright (c) 2014, skyem123 (Skye M.), skyem@hotmail.co.uk\r\nAll rights reserved.\r\n\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions are met:\r\n\r\n* Redistributions of source code must retain the above copyright notice, this\r\n list of conditions and the following disclaimer.\r\n\r\n* Redistributions in binary form must reproduce the above copyright notice,\r\n this list of conditions and the following disclaimer in the documentation\r\n and\/or other materials provided with the distribution.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n--]]\r\n\r\n--component code\r\nfunction component_code()\r\nlocal adding = {}\r\nlocal removing = {}\r\nlocal primaries = {}\r\n\r\n-------------------------------------------------------------------------------\r\n\r\n-- This allows writing component.modem.open(123) instead of writing\r\n-- component.getPrimary(\"modem\").open(123), which may be nicer to read.\r\nsetmetatable(component, { __index = function(_, key)\r\n return component.getPrimary(key)\r\n end })\r\n\r\nfunction component.get(address, componentType)\r\n checkArg(1, address, \"string\")\r\n checkArg(2, componentType, \"string\", \"nil\")\r\n for c in component.list(componentType, true) do\r\n if c:sub(1, address:len()) == address then\r\n return c\r\n end\r\n end\r\n return nil, \"no such component\"\r\nend\r\n\r\nfunction component.isAvailable(componentType)\r\n checkArg(1, componentType, \"string\")\r\n if not primaries[componentType] then\r\n -- This is mostly to avoid out of memory errors preventing proxy\r\n -- creation cause confusion by trying to create the proxy again,\r\n -- causing the oom error to be thrown again.\r\n component.setPrimary(componentType, component.list(componentType, true)())\r\n end\r\n return primaries[componentType] ~= nil\r\nend\r\n\r\nfunction component.isPrimary(address)\r\n local componentType = component.type(address)\r\n if componentType then\r\n if component.isAvailable(componentType) then\r\n return primaries[componentType].address == address\r\n end\r\n end\r\n return false\r\nend\r\n\r\nfunction component.getPrimary(componentType)\r\n checkArg(1, componentType, \"string\")\r\n assert(component.isAvailable(componentType),\r\n \"no primary '\" .. componentType .. \"' available\")\r\n return primaries[componentType]\r\nend\r\n\r\nfunction component.setPrimary(componentType, address)\r\n checkArg(1, componentType, \"string\")\r\n checkArg(2, address, \"string\", \"nil\")\r\n if address ~= nil then\r\n address = component.get(address, componentType)\r\n assert(address, \"no such component\")\r\n end\r\n\r\n local wasAvailable = primaries[componentType]\r\n if wasAvailable and address == wasAvailable.address then\r\n return\r\n end\r\n local wasAdding = adding[componentType]\r\n if wasAdding and address == wasAdding.address then\r\n return\r\n end\r\n if wasAdding then\r\n event.cancel(wasAdding.timer)\r\n end\r\n primaries[componentType] = nil\r\n adding[componentType] = nil\r\n\r\n local primary = address and component.proxy(address) or nil\r\n if wasAvailable then\r\n computer.pushSignal(\"component_unavailable\", componentType)\r\n end\r\n if primary then\r\n if wasAvailable or wasAdding then\r\n adding[componentType] = {\r\n address=address,\r\n timer=event.timer(0.1, function()\r\n adding[componentType] = nil\r\n primaries[componentType] = primary\r\n computer.pushSignal(\"component_available\", componentType)\r\n end)\r\n }\r\n else\r\n primaries[componentType] = primary\r\n computer.pushSignal(\"component_available\", componentType)\r\n end\r\n end\r\nend\r\n\r\n-------------------------------------------------------------------------------\r\n\r\nlocal function onComponentAdded(_, address, componentType)\r\n if not (primaries[componentType] or adding[componentType]) then\r\n component.setPrimary(componentType, address)\r\n end\r\nend\r\n\r\nlocal function onComponentRemoved(_, address, componentType)\r\n if primaries[componentType] and primaries[componentType].address == address or\r\n adding[componentType] and adding[componentType].address == address\r\n then\r\n component.setPrimary(componentType, component.list(componentType, true)())\r\n end\r\nend\r\n\r\nevent.listen(\"component_added\", onComponentAdded)\r\nevent.listen(\"component_removed\", onComponentRemoved)\r\nend\r\n--text libary\r\nfunction text_code()\r\n local text = {}\r\n \r\n function text.detab(value, tabWidth)\r\n checkArg(1, value, \"string\")\r\n checkArg(2, tabWidth, \"number\", \"nil\")\r\n tabWidth = tabWidth or 8\r\n local function rep(match)\r\n local spaces = tabWidth - match:len() % tabWidth\r\n return match .. string.rep(\" \", spaces)\r\n end\r\n local result = value:gsub(\"([^\\n]-)\\t\", rep) -- truncate results\r\n return result\r\n end\r\n \r\n\tfunction text.split(s, delimiter)\r\n\t\tresult = {};\r\n\t\tfor match in (s..delimiter):gmatch(\"(.-)\"..delimiter) do\r\n\t\t\ttable.insert(result, match);\r\n\t\tend\r\n\t\treturn result;\r\n\tend\r\n\t\r\n\tfunction text.combine(tbl, delimiter)\r\n\t\tlocal s = \"\"\r\n\t\tfor i,w in pairs(tbl) do\r\n\t\t\tif (i == #tbl) then\r\n\t\t\t\ts = s..w\r\n\t\t\telse\r\n\t\t\t\ts = s..w..\" \"\r\n\t\t\tend\r\n\t\tend\r\n\t\treturn s\r\n\tend\r\n \r\n function text.padRight(value, length)\r\n checkArg(1, value, \"string\", \"nil\")\r\n checkArg(2, length, \"number\")\r\n if not value or unicode.len(value) == 0 then\r\n return string.rep(\" \", length)\r\n else\r\n return value .. string.rep(\" \", length - unicode.len(value))\r\n end\r\n end\r\n \r\n function text.padLeft(value, length)\r\n checkArg(1, value, \"string\", \"nil\")\r\n checkArg(2, length, \"number\")\r\n if not value or unicode.len(value) == 0 then\r\n return string.rep(\" \", length)\r\n else\r\n return string.rep(\" \", length - unicode.len(value)) .. value\r\n end\r\n end\r\n \r\n function text.trim(value) -- from http:\/\/lua-users.org\/wiki\/StringTrim\r\n local from = string.match(value, \"^%s*()\")\r\n return from > #value and \"\" or string.match(value, \".*%S\", from)\r\n end\r\n \r\n function text.wrap(value, width, maxWidth)\r\n checkArg(1, value, \"string\")\r\n checkArg(2, width, \"number\")\r\n checkArg(3, maxWidth, \"number\")\r\n local line, nl = value:match(\"([^\\r\\n]*)(\\r?\\n?)\") -- read until newline\r\n if unicode.len(line) > width then -- do we even need to wrap?\r\n local partial = unicode.sub(line, 1, width)\r\n local wrapped = partial:match(\"(.*[^a-zA-Z0-9._()'`=])\")\r\n if wrapped or unicode.len(line) > maxWidth then\r\n partial = wrapped or partial\r\n return partial, unicode.sub(value, unicode.len(partial) + 1), true\r\n else\r\n return \"\", value, true -- write in new line.\r\n end\r\n end\r\n local start = unicode.len(line) + unicode.len(nl) + 1\r\n return line, start <= unicode.len(value) and unicode.sub(value, start) or nil, unicode.len(nl) > 0\r\n end\r\n \r\n function text.wrappedLines(value, width, maxWidth)\r\n local line, nl\r\n return function()\r\n if value then\r\n line, value, nl = text.wrap(value, width, maxWidth)\r\n return line\r\n end\r\n end\r\n end\r\n \r\n -------------------------------------------------------------------------------\r\n \r\n function text.tokenize(value)\r\n checkArg(1, value, \"string\")\r\n local tokens, token = {}, \"\"\r\n local escaped, quoted, start = false, false, -1\r\n for i = 1, unicode.len(value) do\r\n local char = unicode.sub(value, i, i)\r\n if escaped then -- escaped character\r\n escaped = false\r\n token = token .. char\r\n elseif char == \"\\\\\" and quoted ~= \"'\" then -- escape character?\r\n escaped = true\r\n token = token .. char\r\n elseif char == quoted then -- end of quoted string\r\n quoted = false\r\n token = token .. char\r\n elseif (char == \"'\" or char == '\"') and not quoted then\r\n quoted = char\r\n start = i\r\n token = token .. char\r\n elseif string.find(char, \"%s\") and not quoted then -- delimiter\r\n if token ~= \"\" then\r\n table.insert(tokens, token)\r\n token = \"\"\r\n end\r\n else -- normal char\r\n token = token .. char\r\n end\r\n end\r\n if quoted then\r\n return nil, \"unclosed quote at index \" .. start\r\n end\r\n if token ~= \"\" then\r\n table.insert(tokens, token)\r\n end\r\n return tokens\r\n end\r\n \r\n -------------------------------------------------------------------------------\r\n \r\n function text.endswith(s, send)\r\n return #s >= #send and s:find(send, #s-#send+1, true) and true or false\r\n end\r\n \r\n return text\r\nend\r\n--event code\r\nfunction event_code()\r\n local event, listeners, timers = {}, {}, {}\r\n local lastInterrupt = -math.huge\r\n \r\n local function matches(signal, name, filter)\r\n if name and not (type(signal[1]) == \"string\" and signal[1]:match(name))\r\n then\r\n return false\r\n end\r\n for i = 1, filter.n do\r\n if filter[i] ~= nil and filter[i] ~= signal[i + 1] then\r\n return false\r\n end\r\n end\r\n return true\r\n end\r\n \r\n local function call(callback, ...)\r\n local result, message = pcall(callback, ...)\r\n if not result and type(event.onError) == \"function\" then\r\n pcall(event.onError, message)\r\n return\r\n end\r\n return message\r\n end\r\n \r\n local function dispatch(signal, ...)\r\n if listeners[signal] then\r\n local function callbacks()\r\n local list = {}\r\n for index, listener in ipairs(listeners[signal]) do\r\n list[index] = listener\r\n end\r\n\t\t--[[for signalName, listenerList in pairs(listeners) do\r\n\t\t\tif (signalName == signal) or (string.find(signal, signalName)) then\r\n\t\t\t\tfor index, listener in pairs(listenerList) do\r\n\t\t\t\t\tlist[index] = listener\r\n\t\t\t\tend\r\n\t\t\tend\r\n\t\tend--]]\r\n return list\r\n end\r\n for _, callback in ipairs(callbacks()) do\r\n if call(callback, signal, ...) == false then\r\n event.ignore(signal, callback) -- alternative method of removing a listener\r\n end\r\n end\r\n end\r\n end\r\n \r\n local function tick()\r\n local function elapsed()\r\n local list = {}\r\n for id, timer in pairs(timers) do\r\n if timer.after <= computer.uptime() then\r\n table.insert(list, timer.callback)\r\n timer.times = timer.times - 1\r\n if timer.times <= 0 then\r\n timers[id] = nil\r\n else\r\n timer.after = computer.uptime() + timer.interval\r\n end\r\n end\r\n end\r\n return list\r\n end\r\n for _, callback in ipairs(elapsed()) do\r\n call(callback)\r\n end\r\n end\r\n \r\n -------------------------------------------------------------------------------\r\n \r\n function event.cancel(timerId)\r\n checkArg(1, timerId, \"number\")\r\n if timers[timerId] then\r\n timers[timerId] = nil\r\n return true\r\n end\r\n return false\r\n end\r\n \r\n function event.ignore(name, callback)\r\n checkArg(1, name, \"string\")\r\n checkArg(2, callback, \"function\")\r\n if listeners[name] then\r\n for i = 1, #listeners[name] do\r\n if listeners[name][i] == callback then\r\n table.remove(listeners[name], i)\r\n if #listeners[name] == 0 then\r\n listeners[name] = nil\r\n end\r\n return true\r\n end\r\n end\r\n end\r\n return false\r\n end\r\n \r\n function event.listen(name, callback)\r\n checkArg(1, name, \"string\")\r\n checkArg(2, callback, \"function\")\r\n if listeners[name] then\r\n for i = 1, #listeners[name] do\r\n if listeners[name][i] == callback then\r\n return false\r\n end\r\n end\r\n else\r\n listeners[name] = {}\r\n end\r\n table.insert(listeners[name], callback)\r\n return true\r\n end\r\n \r\n function event.onError(message)\r\n local log = io.open(\"\/tmp\/event.log\", \"a\")\r\n if log then\r\n log:write(message .. \"\\n\")\r\n log:close()\r\n end\r\n end\r\n \r\n function event.pull(...)\r\n local args = table.pack(...)\r\n local seconds, name, filter\r\n if type(args[1]) == \"string\" then\r\n name = args[1]\r\n filter = table.pack(table.unpack(args, 2, args.n))\r\n else\r\n checkArg(1, args[1], \"number\", \"nil\")\r\n checkArg(2, args[2], \"string\", \"nil\")\r\n seconds = args[1]\r\n name = args[2]\r\n filter = table.pack(table.unpack(args, 3, args.n))\r\n end\r\n \r\n local hasFilter = name ~= nil\r\n if not hasFilter then\r\n for i = 1, filter.n do\r\n hasFilter = hasFilter or filter[i] ~= nil\r\n end\r\n end\r\n \r\n local deadline = seconds and\r\n (computer.uptime() + seconds) or\r\n (hasFilter and math.huge or 0)\r\n repeat\r\n local closest = seconds and deadline or math.huge\r\n for _, timer in pairs(timers) do\r\n closest = math.min(closest, timer.after)\r\n end\r\n local signal = table.pack(computer.pullSignal(closest - computer.uptime()))\r\n if signal.n > 0 then\r\n dispatch(table.unpack(signal, 1, signal.n))\r\n end\r\n tick()\r\n if event.shouldInterrupt() then\r\n lastInterrupt = computer.uptime()\r\n error(\"interrupted\", 0)\r\n end\r\n if not (seconds or hasFilter) or matches(signal, name, filter) then\r\n return table.unpack(signal, 1, signal.n)\r\n end\r\n until computer.uptime() >= deadline\r\n end\r\n \r\n function event.shouldInterrupt()\r\n return computer.uptime() - lastInterrupt > 1 and\r\n keyboard.isControlDown() and\r\n keyboard.isAltDown() and\r\n keyboard.isKeyDown(keyboard.keys.c)\r\n end\r\n \r\n function event.timer(interval, callback, times)\r\n checkArg(1, interval, \"number\")\r\n checkArg(2, callback, \"function\")\r\n checkArg(3, times, \"number\", \"nil\")\r\n local id\r\n repeat\r\n id = math.floor(math.random(1, 0x7FFFFFFF))\r\n until not timers[id]\r\n timers[id] = {\r\n interval = interval,\r\n after = computer.uptime() + interval,\r\n callback = callback,\r\n times = times or 1\r\n }\r\n return id\r\n end\r\n \r\n -------------------------------------------------------------------------------\r\n \r\n return event\r\nend\r\n--filesystem code\r\nfunction fs_code()\r\n local fs = {}\r\n fs.drive = {}\r\n --drive mapping table, initilized later\r\n fs.drive._map = {}\r\n --converts a drive letter into a proxy\r\n function fs.drive.letterToProxy(letter)\r\n\treturn fs.drive._map[letter]\r\n end\r\n --finds the proxy associated with the letter\r\n function fs.drive.proxyToLetter(proxy)\r\n for l,p in pairs(fs.drive._map) do\r\n\t if p == proxy then return l end\r\n\tend\r\n\treturn nil\r\n end\r\n --maps a proxy to a letter\r\n function fs.drive.mapProxy(letter, proxy)\r\n fs.drive._map[letter] = proxy\r\n end\r\n --finds the address of a drive letter.\r\n function fs.drive.toAddress(letter)\r\n return fs.drive._map[letter].address\r\n end\r\n --finds the drive letter mapped to an address\r\n function fs.drive.toLetter(address)\r\n\tfor l,p in pairs(fs.drive._map) do\r\n\t if p.address == address then return l end\r\n\tend\r\n\treturn nil\r\n end\r\n function fs.drive.mapAddress(letter, address)\r\n\t--print(\"mapAddress\")\r\n\tif (not address) then fs.drive._map[letter] = nil end\r\n fs.drive._map[letter] = fs.proxy(address)\r\n end\r\n function fs.drive.autoMap(address) --returns the letter if mapped OR already mapped, false if not.\r\n\t--print(\"autoMap\")\r\n\t--we get the address and see if it already is mapped...\r\n\tlocal l = fs.drive.toLetter(address)\r\n\tif l then return l end\r\n\t--then we take the address and attempt to map it\r\n\t--start at A:\t\r\n\tl = \"A\"\r\n\twhile true do\r\n\t\t--see if it is mapped and then go to the next letter...\r\n\t\tif fs.drive._map[l] then l = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ_'):match(l..'(.)') else fs.drive.mapAddress(l, address) return l end\r\n\t\t--if we got to the end, fail\r\n\t\tif l == \"_\" then return false end\r\n\tend\r\n end\r\n function fs.drive.listProxy()\r\n local t = fs.drive._map\r\n local p = {}\r\n\tfor n in pairs(t) do table.insert(p, n) end\r\n table.sort(p, f)\r\n local i = 0 -- iterator variable\r\n local iter = function () -- iterator function\r\n i = i + 1\r\n if p[i] == nil then return nil\r\n else return p[i], t[p[i]]\r\n end\r\n end\r\n return iter\r\n end\r\n function fs.drive.list()\r\n local i = 0 -- iterator variable\r\n\tlocal proxyIter = fs.drive.listProxy()\r\n local iter = function () -- iterator function\r\n\t l, p = proxyIter()\r\n\t if not l then return nil end\r\n return l, p.address\r\n end\r\n\treturn iter\r\n end\r\n fs.drive._current = \"A\" --as the boot drive is A:\r\n function fs.drive.setcurrent(letter)\r\n\tletter = letter:upper()\r\n if not fs.drive._map[letter] then error(\"Invalid Drive\", 2) end\r\n fs.drive._current = letter\r\n\tend\r\n function fs.drive.getcurrent() return fs.drive._current end\r\n function fs.invoke(method, ...) return fs.drive._map[fs.drive._current][method](...) end\r\n function fs.proxy(filter)\r\n checkArg(1, filter, \"string\")\r\n local address\r\n for c in component.list(\"filesystem\") do\r\n if component.invoke(c, \"getLabel\") == filter then\r\n address = c\r\n break\r\n end\r\n\t if filter:sub(2,2) == \":\" then\r\n\t if fs.drive.toAddress(filter:sub(1,1)) == c then address = c break end\r\n end\r\n\t if c:sub(1, filter:len()) == filter then\r\n address = c\r\n break\r\n end\r\n end\r\n if not address then\r\n return nil, \"no such file system\"\r\n end\r\n return component.proxy(address)\r\n end\r\n function fs.open(file, mode) return fs.invoke(\"open\", file, mode or \"r\") end\r\n function fs.write(handle, data) return fs.invoke(\"write\", handle, data) end\r\n function fs.read(handle, length) return fs.invoke(\"read\", handle, length or math.huge) end\r\n function fs.close(handle) return fs.invoke(\"close\", handle) end\r\n function fs.isDirectory(path) return fs.invoke(\"isDirectory\", path) end\r\n function fs.exists(path) return fs.invoke(\"exists\", path) end\r\n function fs.remove(path) return fs.invoke(\"remove\", path) end\r\n function fs.copy(fromPath, toPath)\r\n if fs.isDirectory(fromPath) then\r\n return nil, \"cannot copy folders\"\r\n end\r\n local input, reason = fs.open(fromPath, \"rb\")\r\n if not input then\r\n return nil, reason\r\n end\r\n local output, reason = fs.open(toPath, \"wb\")\r\n if not output then\r\n fs.close(input)\r\n return nil, reason\r\n end\r\n repeat\r\n local buffer, reason = filesystem.read(input)\r\n if not buffer and reason then\r\n return nil, reason\r\n elseif buffer then\r\n local result, reason = filesystem.write(output, buffer)\r\n if not result then\r\n filesystem.close(input)\r\n filesystem.close(output)\r\n return nil, reason\r\n end\r\n end\r\n until not buffer\r\n filesystem.close(input)\r\n filesystem.close(output)\r\n return true\r\n end\r\n function fs.rename(path1, path2) return fs.invoke(\"rename\", path1, path2) end\r\n function fs.makeDirectory(path) return fs.invoke(\"makeDirectory\", path) end\r\n function fs.list(path)\r\n local i = 0\r\n local t = fs.invoke(\"list\", path)\r\n\tlocal n = #t\r\n return function()\r\n i = i + 1\r\n\t if i <= n then return t[i] end\r\n\t return nil\r\n\tend\r\n end\r\n function fs.listTbl(path)\r\n\tlocal l = fs.invoke(\"list\", path)\r\n\treturn l\r\n end\r\n \r\n --handle inserted and removed filesystems\r\n local function onComponentAdded(_, address, componentType)\r\n if componentType == \"filesystem\" then\r\n local letter = fs.drive.autoMap(address)\r\n\t\tif (letter) then\r\n\t\t\tif (Shell) then\r\n\t\t\t\tShell.print(\"New drive detected, assigned to \"..letter)\r\n\t\t\telse\r\n\t\t\t\tprint(\"New drive detected, assigned to \"..letter)\r\n\t\t\tend\r\n\t\tend\r\n end\r\n end\r\n local function onComponentRemoved(_, address, componentType)\r\n if componentType == \"filesystem\" then\r\n\t local letter = fs.drive.toLetter(address)\r\n\t if (letter) then\r\n\t\tif (Shell) then\r\n\t\t\tShell.print(\"Drive \"..letter..\" removed\")\r\n\t\telse\r\n\t\t\tprint(\"Drive \"..letter..\" removed\")\r\n\t\tend\r\n\t end\r\n fs.drive.mapAddress(letter, nil)\r\n end\r\n end\r\n event.listen(\"component_added\", onComponentAdded)\r\n event.listen(\"component_removed\", onComponentRemoved)\r\n local function driveInit()\r\n local boot = fs.proxy(computer.getBootAddress())\r\n local temp = fs.proxy(computer.tmpAddress())\r\n fs.drive._map = { [\"A\"]=boot, [\"X\"]=temp }\r\n\tfor address, componentType in (component.list(\"filesystem\")) do\r\n\t\tif (componentType == \"filesystem\") and (address ~= computer.getBootAddress()) and (address ~= computer.tmpAddress()) then\r\n\t\t\tfs.drive.autoMap(address)\r\n\t\tend\r\n\tend\r\n end\r\n driveInit()\r\n --return the API\r\n return fs\r\nend\r\n--terminal code\r\nfunction terminal_code()\r\n local term = {}\r\n local cursorX, cursorY = 1, 1\r\n local cursorBlink = nil\r\n \r\n local function toggleBlink()\r\n if term.isAvailable() then\r\n cursorBlink.state = not cursorBlink.state\r\n if cursorBlink.state then\r\n cursorBlink.alt = component.gpu.get(cursorX, cursorY)\r\n component.gpu.set(cursorX, cursorY, \"_\")\r\n else\r\n component.gpu.set(cursorX, cursorY, cursorBlink.alt)\r\n end\r\n end\r\n end\r\n \r\n -------------------------------------------------------------------------------\r\n \r\n function term.clear()\r\n if term.isAvailable() then\r\n local w, h = component.gpu.getResolution()\r\n component.gpu.fill(1, 1, w, h, \" \")\r\n end\r\n cursorX, cursorY = 1, 1\r\n end\r\n \r\n function term.clearLine()\r\n if term.isAvailable() then\r\n local w = component.gpu.getResolution()\r\n component.gpu.fill(1, cursorY, w, 1, \" \")\r\n end\r\n cursorX = 1\r\n end\r\n \r\n function term.getCursor()\r\n return cursorX, cursorY\r\n end\r\n \r\n function term.setCursor(col, row)\r\n checkArg(1, col, \"number\")\r\n checkArg(2, row, \"number\")\r\n if cursorBlink and cursorBlink.state then\r\n toggleBlink()\r\n end\r\n cursorX = math.floor(col)\r\n cursorY = math.floor(row)\r\n end\r\n \r\n function term.getCursorBlink()\r\n return cursorBlink ~= nil\r\n end\r\n \r\n function term.setCursorBlink(enabled)\r\n checkArg(1, enabled, \"boolean\")\r\n if enabled then\r\n if not cursorBlink then\r\n cursorBlink = {}\r\n cursorBlink.id = event.timer(0.5, toggleBlink, math.huge)\r\n cursorBlink.state = false\r\n elseif not cursorBlink.state then\r\n toggleBlink()\r\n end\r\n elseif cursorBlink then\r\n event.cancel(cursorBlink.id)\r\n if cursorBlink.state then\r\n toggleBlink()\r\n end\r\n cursorBlink = nil\r\n end\r\n end\r\n \r\n function term.isAvailable()\r\n return component.isAvailable(\"gpu\") and component.isAvailable(\"screen\")\r\n end\r\n \r\n function term.readKey(echo)\r\n local blink = term.getCursorBlink()\r\n\tterm.setCursorBlink(true)\r\n\tlocal ok, name, address, charOrValue, code = pcall(event.pull, \"key_down\")\r\n if not ok then\r\n term.setCursorBlink(blink)\r\n error(\"interrupted\", 0)\r\n end\r\n\tif name == \"key_down\" then\r\n\t if echo then term.write(charOrValue) end\r\n term.setCursorBlink(blink)\r\n\tend\r\n end\r\n \r\n function term.read(history, dobreak)\r\n checkArg(1, history, \"table\", \"nil\")\r\n history = history or {}\r\n table.insert(history, \"\")\r\n local offset = term.getCursor() - 1\r\n local scrollX, scrollY = 0, #history - 1\r\n \r\n local function getCursor()\r\n local cx, cy = term.getCursor()\r\n return cx - offset + scrollX, 1 + scrollY\r\n end\r\n \r\n local function line()\r\n local cbx, cby = getCursor()\r\n return history[cby]\r\n end\r\n \r\n local function setCursor(nbx, nby)\r\n local w, h = component.gpu.getResolution()\r\n local cx, cy = term.getCursor()\r\n \r\n scrollY = nby - 1\r\n \r\n nbx = math.max(1, math.min(unicode.len(history[nby]) + 1, nbx))\r\n local ncx = nbx + offset - scrollX\r\n if ncx > w then\r\n local sx = nbx - (w - offset)\r\n local dx = math.abs(scrollX - sx)\r\n scrollX = sx\r\n component.gpu.copy(1 + offset + dx, cy, w - offset - dx, 1, -dx, 0)\r\n local str = unicode.sub(history[nby], nbx - (dx - 1), nbx)\r\n str = text.padRight(str, dx)\r\n component.gpu.set(1 + math.max(offset, w - dx), cy, unicode.sub(str, 1 + math.max(0, dx - (w - offset))))\r\n elseif ncx < 1 + offset then\r\n local sx = nbx - 1\r\n local dx = math.abs(scrollX - sx)\r\n scrollX = sx\r\n component.gpu.copy(1 + offset, cy, w - offset - dx, 1, dx, 0)\r\n local str = unicode.sub(history[nby], nbx, nbx + dx)\r\n --str = text.padRight(str, dx)\r\n component.gpu.set(1 + offset, cy, str)\r\n end\r\n \r\n term.setCursor(nbx - scrollX + offset, cy)\r\n end\r\n \r\n local function copyIfNecessary()\r\n local cbx, cby = getCursor()\r\n if cby ~= #history then\r\n history[#history] = line()\r\n setCursor(cbx, #history)\r\n end\r\n end\r\n \r\n local function redraw()\r\n local cx, cy = term.getCursor()\r\n local bx, by = 1 + scrollX, 1 + scrollY\r\n local w, h = component.gpu.getResolution()\r\n local l = w - offset\r\n local str = unicode.sub(history[by], bx, bx + l)\r\n str = text.padRight(str, l)\r\n component.gpu.set(1 + offset, cy, str)\r\n end\r\n \r\n local function home()\r\n local cbx, cby = getCursor()\r\n setCursor(1, cby)\r\n end\r\n \r\n local function ende()\r\n local cbx, cby = getCursor()\r\n setCursor(unicode.len(line()) + 1, cby)\r\n end\r\n \r\n local function left()\r\n local cbx, cby = getCursor()\r\n if cbx > 1 then\r\n setCursor(cbx - 1, cby)\r\n return true -- for backspace\r\n end\r\n end\r\n \r\n local function right(n)\r\n n = n or 1\r\n local cbx, cby = getCursor()\r\n local be = unicode.len(line()) + 1\r\n if cbx < be then\r\n setCursor(math.min(be, cbx + n), cby)\r\n end\r\n end\r\n \r\n local function up()\r\n local cbx, cby = getCursor()\r\n if cby > 1 then\r\n setCursor(1, cby - 1)\r\n redraw()\r\n ende()\r\n end\r\n end\r\n \r\n local function down()\r\n local cbx, cby = getCursor()\r\n if cby < #history then\r\n setCursor(1, cby + 1)\r\n redraw()\r\n ende()\r\n end\r\n end\r\n \r\n local function delete()\r\n copyIfNecessary()\r\n local cbx, cby = getCursor()\r\n if cbx <= unicode.len(line()) then\r\n history[cby] = unicode.sub(line(), 1, cbx - 1) ..\r\n unicode.sub(line(), cbx + 1)\r\n local cx, cy = term.getCursor()\r\n local w, h = component.gpu.getResolution()\r\n component.gpu.copy(cx + 1, cy, w - cx, 1, -1, 0)\r\n local br = cbx + (w - cx)\r\n local char = unicode.sub(line(), br, br)\r\n if not char or unicode.len(char) == 0 then\r\n char = \" \"\r\n end\r\n component.gpu.set(w, cy, char)\r\n end\r\n end\r\n \r\n local function insert(value)\r\n copyIfNecessary()\r\n local cx, cy = term.getCursor()\r\n local cbx, cby = getCursor()\r\n local w, h = component.gpu.getResolution()\r\n history[cby] = unicode.sub(line(), 1, cbx - 1) ..\r\n value ..\r\n unicode.sub(line(), cbx)\r\n local len = unicode.len(value)\r\n local n = w - (cx - 1) - len\r\n if n > 0 then\r\n component.gpu.copy(cx, cy, n, 1, len, 0)\r\n end\r\n component.gpu.set(cx, cy, value)\r\n right(len)\r\n end\r\n \r\n local function onKeyDown(char, code)\r\n term.setCursorBlink(false)\r\n if code == keyboard.keys.back then\r\n if left() then delete() end\r\n elseif code == keyboard.keys.delete then\r\n delete()\r\n elseif code == keyboard.keys.left then\r\n left()\r\n elseif code == keyboard.keys.right then\r\n right()\r\n elseif code == keyboard.keys.home then\r\n home()\r\n elseif code == keyboard.keys[\"end\"] then\r\n ende()\r\n elseif code == keyboard.keys.up then\r\n up()\r\n elseif code == keyboard.keys.down then\r\n down()\r\n elseif code == keyboard.keys.enter then\r\n local cbx, cby = getCursor()\r\n if cby ~= #history then -- bring entry to front\r\n history[#history] = line()\r\n table.remove(history, cby)\r\n end\r\n return true, history[#history] .. \"\\n\"\r\n elseif keyboard.isControlDown() and code == keyboard.keys.d then\r\n if line() == \"\" then\r\n history[#history] = \"\"\r\n return true, nil\r\n end\r\n elseif keyboard.isControlDown() and code == keyboard.keys.c then\r\n history[#history] = \"\"\r\n return true, nil\r\n elseif not keyboard.isControl(char) then\r\n insert(unicode.char(char))\r\n end\r\n term.setCursorBlink(true)\r\n term.setCursorBlink(true) -- force toggle to caret\r\n end\r\n \r\n local function onClipboard(value)\r\n copyIfNecessary()\r\n term.setCursorBlink(false)\r\n local cbx, cby = getCursor()\r\n local l = value:find(\"\\n\", 1, true)\r\n if l then\r\n history[cby] = unicode.sub(line(), 1, cbx - 1)\r\n redraw()\r\n insert(unicode.sub(value, 1, l - 1))\r\n return true, line() .. \"\\n\"\r\n else\r\n insert(value)\r\n term.setCursorBlink(true)\r\n term.setCursorBlink(true) -- force toggle to caret\r\n end\r\n end\r\n \r\n local function cleanup()\r\n if history[#history] == \"\" then\r\n table.remove(history)\r\n end\r\n term.setCursorBlink(false)\r\n if term.getCursor() > 1 and dobreak ~= false then\r\n print()\r\n end\r\n end\r\n \r\n term.setCursorBlink(true)\r\n while term.isAvailable() do\r\n local ocx, ocy = getCursor()\r\n local ok, name, address, charOrValue, code = pcall(event.pull)\r\n if not ok then\r\n cleanup()\r\n error(\"interrupted\", 0)\r\n end\r\n local ncx, ncy = getCursor()\r\n if ocx ~= ncx or ocy ~= ncy then\r\n cleanup()\r\n return \"\" -- soft fail the read if someone messes with the term\r\n end\r\n if term.isAvailable() and -- may have changed since pull\r\n type(address) == \"string\" and\r\n component.isPrimary(address)\r\n then\r\n local done, result\r\n if name == \"key_down\" then\r\n done, result = onKeyDown(charOrValue, code)\r\n elseif name == \"clipboard\" then\r\n done, result = onClipboard(charOrValue)\r\n end\r\n if done then\r\n cleanup()\r\n return result\r\n end\r\n end\r\n end\r\n cleanup()\r\n return nil -- fail the read if term becomes unavailable\r\n end\r\n \r\n function term.write(value, wrap)\r\n if not term.isAvailable() then\r\n return\r\n end\r\n value = tostring(value)\r\n if unicode.len(value) == 0 then\r\n return\r\n end\r\n do\r\n local noBell = value:gsub(\"\\a\", \"\")\r\n if #noBell ~= #value then\r\n value = noBell\r\n computer.beep()\r\n end\r\n end\r\n value = text.detab(value)\r\n local w, h = component.gpu.getResolution()\r\n if not w then\r\n return -- gpu lost its screen but the signal wasn't processed yet.\r\n end\r\n local blink = term.getCursorBlink()\r\n term.setCursorBlink(false)\r\n local line, nl\r\n repeat\r\n local wrapAfter, margin = math.huge, math.huge\r\n if wrap then\r\n wrapAfter, margin = w - (cursorX - 1), w\r\n end\r\n line, value, nl = text.wrap(value, wrapAfter, margin)\r\n component.gpu.set(cursorX, cursorY, line)\r\n cursorX = cursorX + unicode.len(line)\r\n if nl or (cursorX > w and wrap) then\r\n cursorX = 1\r\n cursorY = cursorY + 1\r\n end\r\n if cursorY > h then\r\n component.gpu.copy(1, 1, w, h, 0, -1)\r\n component.gpu.fill(1, h, w, 1, \" \")\r\n cursorY = h\r\n end\r\n until not value\r\n term.setCursorBlink(blink)\r\n end\r\n \r\n -------------------------------------------------------------------------------\r\n \r\n return term\r\nend\r\n\r\nlocal function printProcess(...)\r\n local args = table.pack(...)\r\n local argstr = \"\"\r\n for i = 1, args.n do\r\n local arg = tostring(args[i])\r\n if i > 1 then\r\n arg = \"\\t\" .. arg\r\n end\r\n argstr = argstr .. arg\r\n end\r\n return argstr\r\nend\r\n\r\n--[[function print(...)\r\n term.write(printProcess(...)..\"\\n\", true)\r\nend--]]\r\n\r\nfunction getColor(str)\r\n\tif (str:len() ~= 7) then return end\r\n\tstr = str:upper()\r\n\tstr = str:sub(2)\r\n\tlocal colorNum = tonumber(\"0x\"..str)\r\n\tif (not colorNum) then return end\r\n\treturn colorNum\r\nend\r\n\r\nfunction print(str)\r\n\tif (not str) then term.write(\"\\n\") return end\r\n\tprints(str..\"\\n\")\r\nend\r\n\r\nfunction prints(str)\r\n\tif not term.isAvailable() then return end\r\n\tlocal splitStr = text.split(str, \"&#\")\r\n\tfor i,p in pairs(splitStr) do\r\n\t\tif (i%2 == 0) then -- Tags will be every even entry\r\n\t\t\tlocal cType = p:sub(1,1):upper()\r\n\t\t\tif (cType == \"B\") then\r\n\t\t\t\tlocal color = getColor(p)\r\n\t\t\t\tif (color) then\r\n\t\t\t\t\tcomponent.gpu.setBackground(color)\r\n\t\t\t\tend\r\n\t\t\telseif (cType == \"F\") then\r\n\t\t\t\tlocal color = getColor(p)\r\n\t\t\t\tif (color) then\r\n\t\t\t\t\tcomponent.gpu.setForeground(color)\r\n\t\t\t\tend\r\n\t\t\tend\r\n\t\telse\r\n\t\t\tterm.write(p, true)\r\n\t\tend\r\n\tend\r\nend\r\n\r\nfunction printErr(...)\r\n\tlocal c = component.gpu.getForeground()\r\n\tcomponent.gpu.setForeground(0xFF0000)\r\n\tprint(...)\r\n\tcomponent.gpu.setForeground(c)\r\nend\r\n\r\nfunction printPaged(...)\r\n argstr = printProcess(...) .. \"\\n\"\r\n local i = 0\r\n local p = 0\r\n function readline()\r\n i = string.find(argstr, \"\\n\", i+1) -- find 'next' newline\r\n if i == nil then return nil end\r\n\tlocal out = argstr:sub(p,i)\r\n\tp = i + 1\r\n return out\r\n end\r\n local function readlines(file, line, num)\r\n local w, h = component.gpu.getResolution()\r\n num = num or (h - 1)\r\n\t--num = num or (h)\r\n term.setCursorBlink(false)\r\n for _ = 1, num do\r\n if not line then\r\n line = readline()\r\n if not line then -- eof\r\n return nil\r\n end\r\n end\r\n local wrapped\r\n wrapped, line = text.wrap(text.detab(line), w, w)\r\n term.write(wrapped .. \"\\n\")\r\n end\r\n term.setCursor(1, h)\r\n term.write(\"Press enter or space to continue:\")\r\n term.setCursorBlink(true)\r\n return true\r\n end\r\n\r\n local line = nil\r\n while true do\r\n if not readlines(file, line) then\r\n return\r\n end\r\n while true do\r\n local event, address, char, code = event.pull(\"key_down\")\r\n if component.isPrimary(address) then\r\n if code == keyboard.keys.q then\r\n term.setCursorBlink(false)\r\n term.clearLine()\r\n return\r\n elseif code == keyboard.keys.space or code == keyboard.keys.pageDown then\r\n\t\t term.clearLine()\r\n break\r\n elseif code == keyboard.keys.enter or code == keyboard.keys.down then\r\n term.clearLine()\r\n if not readlines(file, line, 1) then\r\n return\r\n end\r\n end\r\n end\r\n end\r\n end\r\n\r\nend","\/Keyboard.lua":"--[[\r\nCopyright (c) 2014, skyem123 (Skye M.), skyem@hotmail.co.uk\r\nAll rights reserved.\r\n\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions are met:\r\n\r\n* Redistributions of source code must retain the above copyright notice, this\r\n list of conditions and the following disclaimer.\r\n\r\n* Redistributions in binary form must reproduce the above copyright notice,\r\n this list of conditions and the following disclaimer in the documentation\r\n and\/or other materials provided with the distribution.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n--]]\r\n\r\nlocal keyboard = {pressedChars = {}, pressedCodes = {}}\r\n\r\nkeyboard.keys = {\r\n [\"1\"] = 0x02,\r\n [\"2\"] = 0x03,\r\n [\"3\"] = 0x04,\r\n [\"4\"] = 0x05,\r\n [\"5\"] = 0x06,\r\n [\"6\"] = 0x07,\r\n [\"7\"] = 0x08,\r\n [\"8\"] = 0x09,\r\n [\"9\"] = 0x0A,\r\n [\"0\"] = 0x0B,\r\n a = 0x1E,\r\n b = 0x30,\r\n c = 0x2E,\r\n d = 0x20,\r\n e = 0x12,\r\n f = 0x21,\r\n g = 0x22,\r\n h = 0x23,\r\n i = 0x17,\r\n j = 0x24,\r\n k = 0x25,\r\n l = 0x26,\r\n m = 0x32,\r\n n = 0x31,\r\n o = 0x18,\r\n p = 0x19,\r\n q = 0x10,\r\n r = 0x13,\r\n s = 0x1F,\r\n t = 0x14,\r\n u = 0x16,\r\n v = 0x2F,\r\n w = 0x11,\r\n x = 0x2D,\r\n y = 0x15,\r\n z = 0x2C,\r\n\r\n apostrophe = 0x28,\r\n at = 0x91,\r\n back = 0x0E, -- backspace\r\n backslash = 0x2B,\r\n colon = 0x92,\r\n comma = 0x33,\r\n enter = 0x1C,\r\n equals = 0x0D,\r\n grave = 0x29, -- accent grave\r\n lbracket = 0x1A,\r\n lcontrol = 0x1D,\r\n lmenu = 0x38, -- left Alt\r\n lshift = 0x2A,\r\n minus = 0x0C,\r\n numlock = 0x45,\r\n pause = 0xC5,\r\n period = 0x34,\r\n rbracket = 0x1B,\r\n rcontrol = 0x9D,\r\n rmenu = 0xB8, -- right Alt\r\n rshift = 0x36,\r\n scroll = 0x46, -- Scroll Lock\r\n semicolon = 0x27,\r\n slash = 0x35, -- \/ on main keyboard\r\n space = 0x39,\r\n stop = 0x95,\r\n tab = 0x0F,\r\n underline = 0x93,\r\n\r\n -- Keypad (and numpad with numlock off)\r\n up = 0xC8,\r\n down = 0xD0,\r\n left = 0xCB,\r\n right = 0xCD,\r\n home = 0xC7,\r\n [\"end\"] = 0xCF,\r\n pageUp = 0xC9,\r\n pageDown = 0xD1,\r\n insert = 0xD2,\r\n delete = 0xD3,\r\n\r\n -- Function keys\r\n f1 = 0x3B,\r\n f2 = 0x3C,\r\n f3 = 0x3D,\r\n f4 = 0x3E,\r\n f5 = 0x3F,\r\n f6 = 0x40,\r\n f7 = 0x41,\r\n f8 = 0x42,\r\n f9 = 0x43,\r\n f10 = 0x44,\r\n f11 = 0x57,\r\n f12 = 0x58,\r\n f13 = 0x64,\r\n f14 = 0x65,\r\n f15 = 0x66,\r\n f16 = 0x67,\r\n f17 = 0x68,\r\n f18 = 0x69,\r\n f19 = 0x71,\r\n\r\n -- Japanese keyboards\r\n kana = 0x70,\r\n kanji = 0x94,\r\n convert = 0x79,\r\n noconvert = 0x7B,\r\n yen = 0x7D,\r\n circumflex = 0x90,\r\n ax = 0x96,\r\n\r\n -- Numpad\r\n numpad0 = 0x52,\r\n numpad1 = 0x4F,\r\n numpad2 = 0x50,\r\n numpad3 = 0x51,\r\n numpad4 = 0x4B,\r\n numpad5 = 0x4C,\r\n numpad6 = 0x4D,\r\n numpad7 = 0x47,\r\n numpad8 = 0x48,\r\n numpad9 = 0x49,\r\n numpadmul = 0x37,\r\n numpaddiv = 0xB5,\r\n numpadsub = 0x4A,\r\n numpadadd = 0x4E,\r\n numpaddecimal = 0x53,\r\n numpadcomma = 0xB3,\r\n numpadenter = 0x9C,\r\n numpadequals = 0x8D,\r\n}\r\n\r\n-- Create inverse mapping for name lookup.\r\ndo\r\n local keys = {}\r\n for k in pairs(keyboard.keys) do\r\n table.insert(keys, k)\r\n end\r\n for _, k in pairs(keys) do\r\n keyboard.keys[keyboard.keys[k]] = k\r\n end\r\nend\r\n\r\n-------------------------------------------------------------------------------\r\n\r\nfunction keyboard.isAltDown()\r\n return (keyboard.pressedCodes[keyboard.keys.lmenu] or keyboard.pressedCodes[keyboard.keys.rmenu]) ~= nil\r\nend\r\n\r\nfunction keyboard.isControl(char)\r\n return type(char) == \"number\" and (char < 0x20 or (char >= 0x7F and char <= 0x9F))\r\nend\r\n\r\nfunction keyboard.isControlDown()\r\n return (keyboard.pressedCodes[keyboard.keys.lcontrol] or keyboard.pressedCodes[keyboard.keys.rcontrol]) ~= nil\r\nend\r\n\r\nfunction keyboard.isKeyDown(charOrCode)\r\n checkArg(1, charOrCode, \"string\", \"number\")\r\n if type(charOrCode) == \"string\" then\r\n return keyboard.pressedChars[charOrCode]\r\n elseif type(charOrCode) == \"number\" then\r\n return keyboard.pressedCodes[charOrCode]\r\n end\r\nend\r\n\r\nfunction keyboard.isShiftDown()\r\n return (keyboard.pressedCodes[keyboard.keys.lshift] or keyboard.pressedCodes[keyboard.keys.rshift]) ~= nil\r\nend\r\n\r\n-------------------------------------------------------------------------------\r\n\r\nreturn keyboard","\/init.lua":"function bootcode()\r\n\t-- Low level dofile implementation to read the rest of the OS.\r\n\tlocal bootfs = {}\r\n\tfunction bootfs.invoke(method, ...)\r\n\t\treturn component.invoke(computer.getBootAddress(), method, ...)\r\n\tend\r\n\tfunction bootfs.open(file) return bootfs.invoke(\"open\", file) end\r\n\tfunction bootfs.read(handle) return bootfs.invoke(\"read\", handle, math.huge) end\r\n\tfunction bootfs.close(handle) return bootfs.invoke(\"close\", handle) end\r\n\tfunction bootfs.inits(file) return ipairs(bootfs.invoke(\"list\", \"boot\")) end\r\n\tfunction bootfs.isDirectory(path) return bootfs.invoke(\"isDirectory\", path) end\r\n\t-- low-level dofile implementation\r\n\tlocal function loadfile(file, mode, env)\r\n\t\tlocal handle, reason = bootfs.open(file)\r\n\t\tif not handle then\r\n\t\t\terror(reason)\r\n\t\tend\r\n\t\tlocal buffer = \"\"\r\n\t\trepeat\r\n\t\t\tlocal data, reason = bootfs.read(handle)\r\n\t\t\tif not data and reason then\r\n\t\t\t\terror(reason)\r\n\t\t\tend\r\n\t\t\tbuffer = buffer .. (data or \"\")\r\n\t\tuntil not data\r\n\t\tbootfs.close(handle)\r\n\t\tif mode == nil then mode = \"bt\" end\r\n\t\tif env == nil then env = _G end\r\n\t\treturn load(buffer, \"=\" .. file)\r\n\tend\r\n\t_G.loadfile = loadfile\r\nend\r\n\r\nbootcode()\r\n\r\nfunction dofile(file)\r\n\tlocal program, reason = loadfile(file)\r\n\tif program then\r\n\t\tlocal result = table.pack(pcall(program))\r\n\t\tif result[1] then\r\n\t\t\treturn table.unpack(result, 2, result.n)\r\n\t\telse\r\n\t\t\terror(result[2], 3)\r\n\t\tend\r\n\telse\r\n\t\terror(reason, 3)\r\n\tend\r\nend\r\n\r\ndofile(\"\/CoreLibs.lua\")\r\ndofile(\"\/OS.lua\")\r\n\r\nbootcode = nil\r\nloadfile = nil\r\ndofile = nil\r\n\r\n\r\n\r\n"},"Directories":["\/","\/drivers\/","\/miniapps\/","\/modules\/"]}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement