Sirshark10

Untitled

Jul 19th, 2016
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.12 KB | None | 0 0
  1. nativesetfenv = setfenv
  2. nativegetfenv = getfenv
  3. res = {nativesetfenv,nativegetfenv}
  4. if _VERSION == "Lua 5.1" then
  5. -- Install parts of the Lua 5.2 API so that programs can be written against it now
  6. local nativeload = load
  7. local nativeloadstring = loadstring
  8. function load( x, name, mode, env )
  9. if mode ~= nil and mode ~= "t" then
  10. error( "Binary chunk loading prohibited", 2 )
  11. end
  12. local ok, p1, p2 = pcall( function()
  13. if type(x) == "string" then
  14. local result, err = nativeloadstring( x, name )
  15. if result then
  16. if env then
  17. env._ENV = env
  18. nativesetfenv( result, env )
  19. end
  20. return result
  21. else
  22. return nil, err
  23. end
  24. else
  25. local result, err = nativeload( x, name )
  26. if result then
  27. if env then
  28. env._ENV = env
  29. nativesetfenv( result, env )
  30. end
  31. return result
  32. else
  33. return nil, err
  34. end
  35. end
  36. end )
  37. if ok then
  38. return p1, p2
  39. else
  40. error( p1, 2 )
  41. end
  42. end
  43. table.unpack = unpack
  44. table.pack = function( ... ) return { ... } end
  45.  
  46. local nativebit = bit
  47. bit32 = {}
  48. bit32.arshift = nativebit.brshift
  49. bit32.band = nativebit.band
  50. bit32.bnot = nativebit.bnot
  51. bit32.bor = nativebit.bor
  52. bit32.btest = function( a, b ) return nativebit.band(a,b) ~= 0 end
  53. bit32.bxor = nativebit.bxor
  54. bit32.lshift = nativebit.blshift
  55. bit32.rshift = nativebit.blogic_rshift
  56.  
  57. if _CC_DISABLE_LUA51_FEATURES then
  58. -- Remove the Lua 5.1 features that will be removed when we update to Lua 5.2, for compatibility testing.
  59. -- See "disable_lua51_functions" in ComputerCraft.cfg
  60. setfenv = getfenv
  61. getfenv = getfenv
  62. loadstring = loadstring
  63. unpack = unpack
  64. math.log10 = math.log10
  65. table.maxn = table.maxn
  66. bit = bit
  67. end
  68. end
  69.  
  70. -- Install fix for luaj's broken string.sub/string.find
  71. do
  72. local nativestringfind = string.find
  73. local nativestringsub = string.sub
  74. local nativepcall = pcall
  75. local stringCopy = {}
  76. for k,v in pairs(string) do
  77. stringCopy[k] = v
  78. end
  79. stringCopy.sub = function( s, start, _end )
  80. local ok, r = nativepcall( nativestringsub, s, start, _end )
  81. if ok then
  82. if r then
  83. return r .. ""
  84. end
  85. return nil
  86. else
  87. error( r, 2 )
  88. end
  89. end
  90. stringCopy.find = function( s, ... )
  91. return nativestringfind( s .. "", ... );
  92. end
  93. string = stringCopy
  94. end
  95.  
  96. -- Prevent access to metatables or environments of strings, as these are global between all computers
  97. do
  98. nativegetmetatable = getmetatable
  99. local nativeerror = error
  100. local nativetype = type
  101. string_metatable = nativegetmetatable("")
  102. function getmetatable( t )
  103. local mt = nativegetmetatable( t )
  104. if mt == string_metatable then
  105. return mt
  106. else
  107. return mt
  108. end
  109. end
  110. if _VERSION == "Lua 5.1" and not _CC_DISABLE_LUA51_FEATURES then
  111. local string_env = nativegetfenv(("").gsub)
  112. function getfenv( env )
  113. if env == nil then
  114. env = 2
  115. elseif nativetype( env ) == "number" and env > 0 then
  116. env = env + 1
  117. end
  118. local fenv = nativegetfenv(env)
  119. if fenv == string_env then
  120. --nativeerror( "Attempt to access string metatable", 2 )
  121. return nativegetfenv( 0 )
  122. else
  123. return fenv
  124. end
  125. end
  126. end
  127. end
  128.  
  129. -- Install lua parts of the os api
  130. function os.version()
  131. return "CraftOS 1.7"
  132. end
  133.  
  134. function os.pullEventRaw( sFilter )
  135. return coroutine.yield( sFilter )
  136. end
  137.  
  138. function os.pullEvent( sFilter )
  139. local eventData = { os.pullEventRaw( sFilter ) }
  140. if eventData[1] == "terminate" then
  141. error( "Terminated", 0 )
  142. end
  143. return table.unpack( eventData )
  144. end
  145.  
  146. -- Install globals
  147. function sleep( nTime )
  148. local timer = os.startTimer( nTime or 0 )
  149. repeat
  150. local sEvent, param = os.pullEvent( "timer" )
  151. until param == timer
  152. end
  153.  
  154. function write( sText )
  155. local w,h = term.getSize()
  156. local x,y = term.getCursorPos()
  157.  
  158. local nLinesPrinted = 0
  159. local function newLine()
  160. if y + 1 <= h then
  161. term.setCursorPos(1, y + 1)
  162. else
  163. term.setCursorPos(1, h)
  164. term.scroll(1)
  165. end
  166. x, y = term.getCursorPos()
  167. nLinesPrinted = nLinesPrinted + 1
  168. end
  169.  
  170. -- Print the line with proper word wrapping
  171. while string.len(sText) > 0 do
  172. local whitespace = string.match( sText, "^[ \t]+" )
  173. if whitespace then
  174. -- Print whitespace
  175. term.write( whitespace )
  176. x,y = term.getCursorPos()
  177. sText = string.sub( sText, string.len(whitespace) + 1 )
  178. end
  179.  
  180. local newline = string.match( sText, "^\n" )
  181. if newline then
  182. -- Print newlines
  183. newLine()
  184. sText = string.sub( sText, 2 )
  185. end
  186.  
  187. local text = string.match( sText, "^[^ \t\n]+" )
  188. if text then
  189. sText = string.sub( sText, string.len(text) + 1 )
  190. if string.len(text) > w then
  191. -- Print a multiline word
  192. while string.len( text ) > 0 do
  193. if x > w then
  194. newLine()
  195. end
  196. term.write( text )
  197. text = string.sub( text, (w-x) + 2 )
  198. x,y = term.getCursorPos()
  199. end
  200. else
  201. -- Print a word normally
  202. if x + string.len(text) - 1 > w then
  203. newLine()
  204. end
  205. term.write( text )
  206. x,y = term.getCursorPos()
  207. end
  208. end
  209. end
  210.  
  211. return nLinesPrinted
  212. end
  213.  
  214. function print( ... )
  215. local nLinesPrinted = 0
  216. for n,v in ipairs( { ... } ) do
  217. nLinesPrinted = nLinesPrinted + write( tostring( v ) )
  218. end
  219. nLinesPrinted = nLinesPrinted + write( "\n" )
  220. return nLinesPrinted
  221. end
  222.  
  223. function printError( ... )
  224. if term.isColour() then
  225. term.setTextColour( colors.red )
  226. end
  227. print( ... )
  228. if term.isColour() then
  229. term.setTextColour( colors.white )
  230. end
  231. end
  232.  
  233. function read( _sReplaceChar, _tHistory, _fnComplete )
  234. term.setCursorBlink( true )
  235.  
  236. local sLine = ""
  237. local nHistoryPos
  238. local nPos = 0
  239. if _sReplaceChar then
  240. _sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
  241. end
  242.  
  243. local tCompletions
  244. local nCompletion
  245. local function recomplete()
  246. if _fnComplete and nPos == string.len(sLine) then
  247. tCompletions = _fnComplete( sLine )
  248. if tCompletions and #tCompletions > 0 then
  249. nCompletion = 1
  250. else
  251. nCompletion = nil
  252. end
  253. else
  254. tCompletions = nil
  255. nCompletion = nil
  256. end
  257. end
  258.  
  259. local function uncomplete()
  260. tCompletions = nil
  261. nCompletion = nil
  262. end
  263.  
  264. local w = term.getSize()
  265. local sx = term.getCursorPos()
  266.  
  267. local function redraw( _bClear )
  268. local nScroll = 0
  269. if sx + nPos >= w then
  270. nScroll = (sx + nPos) - w
  271. end
  272.  
  273. local cx,cy = term.getCursorPos()
  274. term.setCursorPos( sx, cy )
  275. local sReplace = (_bClear and " ") or _sReplaceChar
  276. if sReplace then
  277. term.write( string.rep( sReplace, math.max( string.len(sLine) - nScroll, 0 ) ) )
  278. else
  279. term.write( string.sub( sLine, nScroll + 1 ) )
  280. end
  281.  
  282. if nCompletion then
  283. local sCompletion = tCompletions[ nCompletion ]
  284. local oldText, oldBg
  285. if not _bClear then
  286. oldText = term.getTextColor()
  287. oldBg = term.getBackgroundColor()
  288. term.setTextColor( colors.white )
  289. term.setBackgroundColor( colors.gray )
  290. end
  291. if sReplace then
  292. term.write( string.rep( sReplace, string.len( sCompletion ) ) )
  293. else
  294. term.write( sCompletion )
  295. end
  296. if not _bClear then
  297. term.setTextColor( oldText )
  298. term.setBackgroundColor( oldBg )
  299. end
  300. end
  301.  
  302. term.setCursorPos( sx + nPos - nScroll, cy )
  303. end
  304.  
  305. local function clear()
  306. redraw( true )
  307. end
  308.  
  309. recomplete()
  310. redraw()
  311.  
  312. local function acceptCompletion()
  313. if nCompletion then
  314. -- Clear
  315. clear()
  316.  
  317. -- Find the common prefix of all the other suggestions which start with the same letter as the current one
  318. local sCompletion = tCompletions[ nCompletion ]
  319. local sFirstLetter = string.sub( sCompletion, 1, 1 )
  320. local sCommonPrefix = sCompletion
  321. for n=1,#tCompletions do
  322. local sResult = tCompletions[n]
  323. if n ~= nCompletion and string.find( sResult, sFirstLetter, 1, true ) == 1 then
  324. while #sCommonPrefix > 1 do
  325. if string.find( sResult, sCommonPrefix, 1, true ) == 1 then
  326. break
  327. else
  328. sCommonPrefix = string.sub( sCommonPrefix, 1, #sCommonPrefix - 1 )
  329. end
  330. end
  331. end
  332. end
  333.  
  334. -- Append this string
  335. sLine = sLine .. sCommonPrefix
  336. nPos = string.len( sLine )
  337. end
  338.  
  339. recomplete()
  340. redraw()
  341. end
  342. while true do
  343. local sEvent, param = os.pullEvent()
  344. if sEvent == "char" then
  345. -- Typed key
  346. clear()
  347. sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
  348. nPos = nPos + 1
  349. recomplete()
  350. redraw()
  351.  
  352. elseif sEvent == "paste" then
  353. -- Pasted text
  354. clear()
  355. sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
  356. nPos = nPos + string.len( param )
  357. recomplete()
  358. redraw()
  359.  
  360. elseif sEvent == "key" then
  361. if param == keys.enter then
  362. -- Enter
  363. if nCompletion then
  364. clear()
  365. uncomplete()
  366. redraw()
  367. end
  368. break
  369.  
  370. elseif param == keys.left then
  371. -- Left
  372. if nPos > 0 then
  373. clear()
  374. nPos = nPos - 1
  375. recomplete()
  376. redraw()
  377. end
  378.  
  379. elseif param == keys.right then
  380. -- Right
  381. if nPos < string.len(sLine) then
  382. -- Move right
  383. clear()
  384. nPos = nPos + 1
  385. recomplete()
  386. redraw()
  387. else
  388. -- Accept autocomplete
  389. acceptCompletion()
  390. end
  391.  
  392. elseif param == keys.up or param == keys.down then
  393. -- Up or down
  394. if nCompletion then
  395. -- Cycle completions
  396. clear()
  397. if param == keys.up then
  398. nCompletion = nCompletion - 1
  399. if nCompletion < 1 then
  400. nCompletion = #tCompletions
  401. end
  402. elseif param == keys.down then
  403. nCompletion = nCompletion + 1
  404. if nCompletion > #tCompletions then
  405. nCompletion = 1
  406. end
  407. end
  408. redraw()
  409.  
  410. elseif _tHistory then
  411. -- Cycle history
  412. clear()
  413. if param == keys.up then
  414. -- Up
  415. if nHistoryPos == nil then
  416. if #_tHistory > 0 then
  417. nHistoryPos = #_tHistory
  418. end
  419. elseif nHistoryPos > 1 then
  420. nHistoryPos = nHistoryPos - 1
  421. end
  422. else
  423. -- Down
  424. if nHistoryPos == #_tHistory then
  425. nHistoryPos = nil
  426. elseif nHistoryPos ~= nil then
  427. nHistoryPos = nHistoryPos + 1
  428. end
  429. end
  430. if nHistoryPos then
  431. sLine = _tHistory[nHistoryPos]
  432. nPos = string.len( sLine )
  433. else
  434. sLine = ""
  435. nPos = 0
  436. end
  437. uncomplete()
  438. redraw()
  439.  
  440. end
  441.  
  442. elseif param == keys.backspace then
  443. -- Backspace
  444. if nPos > 0 then
  445. clear()
  446. sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
  447. nPos = nPos - 1
  448. recomplete()
  449. redraw()
  450. end
  451.  
  452. elseif param == keys.home then
  453. -- Home
  454. if nPos > 0 then
  455. clear()
  456. nPos = 0
  457. recomplete()
  458. redraw()
  459. end
  460.  
  461. elseif param == keys.delete then
  462. -- Delete
  463. if nPos < string.len(sLine) then
  464. clear()
  465. sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )
  466. recomplete()
  467. redraw()
  468. end
  469.  
  470. elseif param == keys["end"] then
  471. -- End
  472. if nPos < string.len(sLine ) then
  473. clear()
  474. nPos = string.len(sLine)
  475. recomplete()
  476. redraw()
  477. end
  478.  
  479. elseif param == keys.tab then
  480. -- Tab (accept autocomplete)
  481. acceptCompletion()
  482.  
  483. end
  484.  
  485. elseif sEvent == "term_resize" then
  486. -- Terminal resized
  487. w = term.getSize()
  488. redraw()
  489.  
  490. end
  491. end
  492.  
  493. local cx, cy = term.getCursorPos()
  494. term.setCursorBlink( false )
  495. term.setCursorPos( w + 1, cy )
  496. print()
  497.  
  498. return sLine
  499. end
  500.  
  501. loadfile = function( _sFile, _tEnv )
  502. local file = fs.open( _sFile, "r" )
  503. if file then
  504. local func, err = load( file.readAll(), fs.getName( _sFile ), "t", _tEnv )
  505. file.close()
  506. return func, err
  507. end
  508. return nil, "File not found"
  509. end
  510.  
  511. if _VERSION == "Lua 5.1" and not _CC_DISABLE_LUA51_FEATURES then
  512. dofile = function( _sFile )
  513. local fnFile, e = loadfile( _sFile )
  514. if fnFile then
  515. setfenv( fnFile, getfenv(2) )
  516. return fnFile()
  517. else
  518. error( e, 2 )
  519. end
  520. end
  521. end
  522.  
  523. -- Install the rest of the OS api
  524. function os.run( _tEnv, _sPath, ... )
  525. local tArgs = { ... }
  526. local tEnv = _tEnv
  527. setmetatable( tEnv, { __index = _G } )
  528. local fnFile, err = loadfile( _sPath, tEnv )
  529. if fnFile then
  530. local ok, err = pcall( function()
  531. fnFile( table.unpack( tArgs ) )
  532. end )
  533. if not ok then
  534. if err and err ~= "" then
  535. printError( err )
  536. end
  537. return false
  538. end
  539. return true
  540. end
  541. if err and err ~= "" then
  542. printError( err )
  543. end
  544. return false
  545. end
  546.  
  547. local tAPIsLoading = {}
  548. function os.loadAPI( _sPath )
  549. local sName = fs.getName( _sPath )
  550. if tAPIsLoading[sName] == true then
  551. printError( "API "..sName.." is already being loaded" )
  552. return false
  553. end
  554. tAPIsLoading[sName] = true
  555.  
  556. local tEnv = {}
  557. setmetatable( tEnv, { __index = _G } )
  558. local fnAPI, err = loadfile( _sPath, tEnv )
  559. if fnAPI then
  560. local ok, err = pcall( fnAPI )
  561. if not ok then
  562. printError( err )
  563. tAPIsLoading[sName] = nil
  564. return false
  565. end
  566. else
  567. printError( err )
  568. tAPIsLoading[sName] = nil
  569. return false
  570. end
  571.  
  572. local tAPI = {}
  573. for k,v in pairs( tEnv ) do
  574. if k ~= "_ENV" then
  575. tAPI[k] = v
  576. end
  577. end
  578.  
  579. _G[sName] = tAPI
  580. tAPIsLoading[sName] = nil
  581. return true
  582. end
  583.  
  584. function os.unloadAPI( _sName )
  585. if _sName ~= "_G" and type(_G[_sName]) == "table" then
  586. _G[_sName] = nil
  587. end
  588. end
  589.  
  590. function os.sleep( nTime )
  591. sleep( nTime )
  592. end
  593.  
  594. local nativeShutdown = os.shutdown
  595. function os.shutdown()
  596. nativeShutdown()
  597. while true do
  598. coroutine.yield()
  599. end
  600. end
  601.  
  602. local nativeReboot = os.reboot
  603. function os.reboot()
  604. nativeReboot()
  605. while true do
  606. coroutine.yield()
  607. end
  608. end
  609.  
  610. -- Install the lua part of the HTTP api (if enabled)
  611. if http then
  612. local nativeHTTPRequest = http.request
  613.  
  614. local function wrapRequest( _url, _post, _headers )
  615. local ok, err = nativeHTTPRequest( _url, _post, _headers )
  616. if ok then
  617. while true do
  618. local event, param1, param2 = os.pullEvent()
  619. if event == "http_success" and param1 == _url then
  620. return param2
  621. elseif event == "http_failure" and param1 == _url then
  622. return nil, param2
  623. end
  624. end
  625. end
  626. return nil, err
  627. end
  628.  
  629. http.get = function( _url, _headers )
  630. return wrapRequest( _url, nil, _headers )
  631. end
  632.  
  633. http.post = function( _url, _post, _headers )
  634. return wrapRequest( _url, _post or "", _headers )
  635. end
  636.  
  637. http.request = function( _url, _post, _headers )
  638. local ok, err = nativeHTTPRequest( _url, _post, _headers )
  639. if not ok then
  640. os.queueEvent( "http_failure", _url, err )
  641. end
  642. return ok, err
  643. end
  644. end
  645.  
  646. -- Install the lua part of the FS api
  647. local tEmpty = {}
  648. function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs )
  649. bIncludeFiles = (bIncludeFiles ~= false)
  650. bIncludeDirs = (bIncludeDirs ~= false)
  651. local sDir = sLocation
  652. local nStart = 1
  653. local nSlash = string.find( sPath, "[/\\]", nStart )
  654. if nSlash == 1 then
  655. sDir = ""
  656. nStart = 2
  657. end
  658. local sName
  659. while not sName do
  660. local nSlash = string.find( sPath, "[/\\]", nStart )
  661. if nSlash then
  662. local sPart = string.sub( sPath, nStart, nSlash - 1 )
  663. sDir = fs.combine( sDir, sPart )
  664. nStart = nSlash + 1
  665. else
  666. sName = string.sub( sPath, nStart )
  667. end
  668. end
  669.  
  670. if fs.isDir( sDir ) then
  671. local tResults = {}
  672. if bIncludeDirs and sPath == "" then
  673. table.insert( tResults, "." )
  674. end
  675. if sDir ~= "" then
  676. if sPath == "" then
  677. table.insert( tResults, (bIncludeDirs and "..") or "../" )
  678. elseif sPath == "." then
  679. table.insert( tResults, (bIncludeDirs and ".") or "./" )
  680. end
  681. end
  682. local tFiles = fs.list( sDir )
  683. for n=1,#tFiles do
  684. local sFile = tFiles[n]
  685. if #sFile >= #sName and string.sub( sFile, 1, #sName ) == sName then
  686. local bIsDir = fs.isDir( fs.combine( sDir, sFile ) )
  687. local sResult = string.sub( sFile, #sName + 1 )
  688. if bIsDir then
  689. table.insert( tResults, sResult .. "/" )
  690. if bIncludeDirs and #sResult > 0 then
  691. table.insert( tResults, sResult )
  692. end
  693. else
  694. if bIncludeFiles and #sResult > 0 then
  695. table.insert( tResults, sResult )
  696. end
  697. end
  698. end
  699. end
  700. return tResults
  701. end
  702. return tEmpty
  703. end
  704.  
  705. -- Load APIs
  706. local bAPIError = false
  707. local tApis = fs.list( "rom/apis" )
  708. for n,sFile in ipairs( tApis ) do
  709. if string.sub( sFile, 1, 1 ) ~= "." then
  710. local sPath = fs.combine( "rom/apis", sFile )
  711. if not fs.isDir( sPath ) then
  712. if not os.loadAPI( sPath ) then
  713. bAPIError = true
  714. end
  715. end
  716. end
  717. end
  718.  
  719. if turtle then
  720. -- Load turtle APIs
  721. local tApis = fs.list( "rom/apis/turtle" )
  722. for n,sFile in ipairs( tApis ) do
  723. if string.sub( sFile, 1, 1 ) ~= "." then
  724. local sPath = fs.combine( "rom/apis/turtle", sFile )
  725. if not fs.isDir( sPath ) then
  726. if not os.loadAPI( sPath ) then
  727. bAPIError = true
  728. end
  729. end
  730. end
  731. end
  732. end
  733.  
  734. if pocket and fs.isDir( "rom/apis/pocket" ) then
  735. -- Load pocket APIs
  736. local tApis = fs.list( "rom/apis/pocket" )
  737. for n,sFile in ipairs( tApis ) do
  738. if string.sub( sFile, 1, 1 ) ~= "." then
  739. local sPath = fs.combine( "rom/apis/pocket", sFile )
  740. if not fs.isDir( sPath ) then
  741. if not os.loadAPI( sPath ) then
  742. bAPIError = true
  743. end
  744. end
  745. end
  746. end
  747. end
  748.  
  749. if commands and fs.isDir( "rom/apis/command" ) then
  750. -- Load command APIs
  751. if os.loadAPI( "rom/apis/command/commands" ) then
  752. -- Add a special case-insensitive metatable to the commands api
  753. local tCaseInsensitiveMetatable = {
  754. __index = function( table, key )
  755. local value = rawget( table, key )
  756. if value ~= nil then
  757. return value
  758. end
  759. if type(key) == "string" then
  760. local value = rawget( table, string.lower(key) )
  761. if value ~= nil then
  762. return value
  763. end
  764. end
  765. return nil
  766. end
  767. }
  768. setmetatable( commands, tCaseInsensitiveMetatable )
  769. setmetatable( commands.async, tCaseInsensitiveMetatable )
  770.  
  771. -- Add global "exec" function
  772. exec = commands.exec
  773. else
  774. bAPIError = true
  775. end
  776. end
  777.  
  778. if bAPIError then
  779. print( "Press any key to continue" )
  780. os.pullEvent( "key" )
  781. term.clear()
  782. term.setCursorPos( 1,1 )
  783. end
  784.  
  785. -- Run the shell
  786. local ok, err = pcall( function()
  787. parallel.waitForAny(
  788. function()
  789. if term.isColour() then
  790. getfenv = nativegetfenv
  791. setfenv = nativesetfenv
  792. os.run( {}, "rom/programs/advanced/multishell" )
  793. else
  794. getfenv = nativegetfenv
  795. setfenv = nativesetfenv
  796. os.run( {}, "rom/programs/shell" )
  797. end
  798. os.run( {}, "rom/programs/shutdown" )
  799. end,
  800. function()
  801. rednet.run()
  802. end )
  803. end )
  804.  
  805. -- If the shell errored, let the user read it.
  806. term.redirect( term.native() )
  807. if not ok then
  808. printError( err )
  809. pcall( function()
  810. term.setCursorBlink( false )
  811. print( "Press any key to continue" )
  812. os.pullEvent( "key" )
  813. end )
  814. end
  815.  
  816. -- End
  817. os.shutdown()
Advertisement
Add Comment
Please, Sign In to add comment