1088b4f5fSWarner Losh-- 2088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 3088b4f5fSWarner Losh-- All rights reserved. 4088b4f5fSWarner Losh-- 5088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 6088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 7088b4f5fSWarner Losh-- are met: 8088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 9088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 10088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 11088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 12088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 13088b4f5fSWarner Losh-- 14088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24088b4f5fSWarner Losh-- SUCH DAMAGE. 25088b4f5fSWarner Losh-- 26088b4f5fSWarner Losh-- $FreeBSD$ 27088b4f5fSWarner Losh-- 28088b4f5fSWarner Losh 29088b4f5fSWarner Losh 30088b4f5fSWarner Loshlocal core = require("core"); 31088b4f5fSWarner Loshlocal color = require("color"); 32088b4f5fSWarner Loshlocal config = require("config"); 33088b4f5fSWarner Loshlocal screen = require("screen"); 34088b4f5fSWarner Loshlocal drawer = require("drawer"); 35088b4f5fSWarner Losh 36*c8518398SKyle Evanslocal menu = {}; 37*c8518398SKyle Evans 38088b4f5fSWarner Loshlocal OnOff; 39088b4f5fSWarner Loshlocal skip; 40088b4f5fSWarner Loshlocal run; 41088b4f5fSWarner Loshlocal autoboot; 42ada26c4aSKyle Evanslocal carousel_choices = {}; 43088b4f5fSWarner Losh 44280e990bSKyle Evans-- loader menu tree is rooted at menu.welcome 45088b4f5fSWarner Losh 46088b4f5fSWarner Loshmenu.boot_options = { 47d8757746SKyle Evans entries = { 48088b4f5fSWarner Losh -- return to welcome menu 49088b4f5fSWarner Losh { 50a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 51088b4f5fSWarner Losh name = function() 5257099121SKyle Evans return "Back to main menu" .. 5357099121SKyle Evans color.highlight(" [Backspace]"); 541666dfc0SKyle Evans end 55088b4f5fSWarner Losh }, 56088b4f5fSWarner Losh 57088b4f5fSWarner Losh -- load defaults 58088b4f5fSWarner Losh { 59a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 60088b4f5fSWarner Losh name = function() 6157099121SKyle Evans return "Load System " .. color.highlight("D") .. 6257099121SKyle Evans "efaults"; 63088b4f5fSWarner Losh end, 64088b4f5fSWarner Losh func = function() 6524a1bd54SKyle Evans core.setDefaults(); 66088b4f5fSWarner Losh end, 67088b4f5fSWarner Losh alias = {"d", "D"} 68088b4f5fSWarner Losh }, 69088b4f5fSWarner Losh 70088b4f5fSWarner Losh { 71a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 72088b4f5fSWarner Losh name = function() 73088b4f5fSWarner Losh return ""; 74088b4f5fSWarner Losh end 75088b4f5fSWarner Losh }, 76088b4f5fSWarner Losh 77088b4f5fSWarner Losh { 78a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 79088b4f5fSWarner Losh name = function() 80088b4f5fSWarner Losh return "Boot Options:"; 81088b4f5fSWarner Losh end 82088b4f5fSWarner Losh }, 83088b4f5fSWarner Losh 84088b4f5fSWarner Losh -- acpi 85088b4f5fSWarner Losh { 86a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 87088b4f5fSWarner Losh name = function() 88fd2b19b3SKyle Evans return OnOff(color.highlight("A") .. 89fd2b19b3SKyle Evans "CPI :", core.acpi); 90088b4f5fSWarner Losh end, 91088b4f5fSWarner Losh func = function() 92088b4f5fSWarner Losh core.setACPI(); 93088b4f5fSWarner Losh end, 94088b4f5fSWarner Losh alias = {"a", "A"} 95088b4f5fSWarner Losh }, 96088b4f5fSWarner Losh -- safe mode 97088b4f5fSWarner Losh { 98a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 99088b4f5fSWarner Losh name = function() 10057099121SKyle Evans return OnOff("Safe " .. color.highlight("M") .. 10157099121SKyle Evans "ode :", core.sm); 102088b4f5fSWarner Losh end, 103088b4f5fSWarner Losh func = function() 104088b4f5fSWarner Losh core.setSafeMode(); 105088b4f5fSWarner Losh end, 106088b4f5fSWarner Losh alias = {"m", "M"} 107088b4f5fSWarner Losh }, 108088b4f5fSWarner Losh -- single user 109088b4f5fSWarner Losh { 110a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 111088b4f5fSWarner Losh name = function() 112fd2b19b3SKyle Evans return OnOff(color.highlight("S") .. 113fd2b19b3SKyle Evans "ingle user:", core.su); 114088b4f5fSWarner Losh end, 115088b4f5fSWarner Losh func = function() 116088b4f5fSWarner Losh core.setSingleUser(); 117088b4f5fSWarner Losh end, 118088b4f5fSWarner Losh alias = {"s", "S"} 119088b4f5fSWarner Losh }, 120088b4f5fSWarner Losh -- verbose boot 121088b4f5fSWarner Losh { 122a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 123088b4f5fSWarner Losh name = function() 124fd2b19b3SKyle Evans return OnOff(color.highlight("V") .. 125fd2b19b3SKyle Evans "erbose :", core.verbose); 126088b4f5fSWarner Losh end, 127088b4f5fSWarner Losh func = function() 128088b4f5fSWarner Losh core.setVerbose(); 129088b4f5fSWarner Losh end, 130088b4f5fSWarner Losh alias = {"v", "V"} 131088b4f5fSWarner Losh }, 132d8757746SKyle Evans }, 133088b4f5fSWarner Losh}; 134088b4f5fSWarner Losh 135088b4f5fSWarner Loshmenu.welcome = { 136303253e5SKyle Evans entries = function() 137303253e5SKyle Evans local menu_entries = menu.welcome.all_entries; 138303253e5SKyle Evans -- Swap the first two menu items on single user boot 139303253e5SKyle Evans if (core.isSingleUserBoot()) then 1405c1b5165SKyle Evans -- Shallow copy the table 1415c1b5165SKyle Evans menu_entries = core.shallowCopyTable(menu_entries); 1425c1b5165SKyle Evans 143303253e5SKyle Evans local multiuser = menu_entries[1]; 144303253e5SKyle Evans local singleuser = menu_entries[2]; 145303253e5SKyle Evans 1465c1b5165SKyle Evans multiuser.name = multiuser.alternate_name; 1475c1b5165SKyle Evans singleuser.name = singleuser.alternate_name; 1485c1b5165SKyle Evans 149303253e5SKyle Evans menu_entries[2] = multiuser; 150303253e5SKyle Evans menu_entries[1] = singleuser; 151303253e5SKyle Evans end 152303253e5SKyle Evans return menu_entries; 153303253e5SKyle Evans end, 154303253e5SKyle Evans all_entries = { 155088b4f5fSWarner Losh -- boot multi user 156088b4f5fSWarner Losh { 157a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 158088b4f5fSWarner Losh name = function() 159fd2b19b3SKyle Evans return color.highlight("B") .. 160fd2b19b3SKyle Evans "oot Multi user " .. 16157099121SKyle Evans color.highlight("[Enter]"); 162088b4f5fSWarner Losh end, 1635c1b5165SKyle Evans -- Not a standard menu entry function! 1645c1b5165SKyle Evans alternate_name = function() 1655c1b5165SKyle Evans return color.highlight("B") .. 1665c1b5165SKyle Evans "oot Multi user"; 1675c1b5165SKyle Evans end, 168088b4f5fSWarner Losh func = function() 169088b4f5fSWarner Losh core.setSingleUser(false); 170088b4f5fSWarner Losh core.boot(); 171088b4f5fSWarner Losh end, 172b458bf0dSKyle Evans alias = {"b", "B"} 173088b4f5fSWarner Losh }, 174088b4f5fSWarner Losh 175088b4f5fSWarner Losh -- boot single user 176088b4f5fSWarner Losh { 177a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 178088b4f5fSWarner Losh name = function() 179fd2b19b3SKyle Evans return "Boot " .. color.highlight("S") .. 180fd2b19b3SKyle Evans "ingle user"; 181088b4f5fSWarner Losh end, 1825c1b5165SKyle Evans -- Not a standard menu entry function! 1835c1b5165SKyle Evans alternate_name = function() 1845c1b5165SKyle Evans return "Boot " .. color.highlight("S") .. 1855c1b5165SKyle Evans "ingle user " .. color.highlight("[Enter]"); 1865c1b5165SKyle Evans end, 187088b4f5fSWarner Losh func = function() 188088b4f5fSWarner Losh core.setSingleUser(true); 189088b4f5fSWarner Losh core.boot(); 190088b4f5fSWarner Losh end, 191088b4f5fSWarner Losh alias = {"s", "S"} 192088b4f5fSWarner Losh }, 193088b4f5fSWarner Losh 194088b4f5fSWarner Losh -- escape to interpreter 195088b4f5fSWarner Losh { 196a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 197088b4f5fSWarner Losh name = function() 198fd2b19b3SKyle Evans return color.highlight("Esc") .. 199fd2b19b3SKyle Evans "ape to loader prompt"; 200088b4f5fSWarner Losh end, 201ef625845SKyle Evans func = function() 20224a1bd54SKyle Evans loader.setenv("autoboot_delay", "NO"); 203ef625845SKyle Evans end, 20439006570SKyle Evans alias = {core.KEYSTR_ESCAPE} 205088b4f5fSWarner Losh }, 206088b4f5fSWarner Losh 207088b4f5fSWarner Losh -- reboot 208088b4f5fSWarner Losh { 209a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 210088b4f5fSWarner Losh name = function() 211088b4f5fSWarner Losh return color.highlight("R") .. "eboot"; 212088b4f5fSWarner Losh end, 213088b4f5fSWarner Losh func = function() 214088b4f5fSWarner Losh loader.perform("reboot"); 215088b4f5fSWarner Losh end, 216088b4f5fSWarner Losh alias = {"r", "R"} 217088b4f5fSWarner Losh }, 218088b4f5fSWarner Losh 219088b4f5fSWarner Losh 220088b4f5fSWarner Losh { 221a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 222088b4f5fSWarner Losh name = function() 223088b4f5fSWarner Losh return ""; 224088b4f5fSWarner Losh end 225088b4f5fSWarner Losh }, 226088b4f5fSWarner Losh 227088b4f5fSWarner Losh { 228a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 229088b4f5fSWarner Losh name = function() 230088b4f5fSWarner Losh return "Options:"; 231088b4f5fSWarner Losh end 232088b4f5fSWarner Losh }, 233088b4f5fSWarner Losh 234088b4f5fSWarner Losh -- kernel options 235088b4f5fSWarner Losh { 236a7cf0562SKyle Evans entry_type = core.MENU_CAROUSEL_ENTRY, 237ada26c4aSKyle Evans carousel_id = "kernel", 238ada26c4aSKyle Evans items = core.kernelList, 239ada26c4aSKyle Evans name = function(idx, choice, all_choices) 24024a1bd54SKyle Evans if (#all_choices == 0) then 241b1b1f2b8SKyle Evans return "Kernel: "; 242088b4f5fSWarner Losh end 243b1b1f2b8SKyle Evans 244bcf48a15SKyle Evans local is_default = (idx == 1); 245bcf48a15SKyle Evans local kernel_name = ""; 246bcf48a15SKyle Evans local name_color; 24724a1bd54SKyle Evans if (is_default) then 248bcf48a15SKyle Evans name_color = color.escapef(color.GREEN); 249bcf48a15SKyle Evans kernel_name = "default/"; 250bcf48a15SKyle Evans else 251bcf48a15SKyle Evans name_color = color.escapef(color.BLUE); 252b1b1f2b8SKyle Evans end 253fd2b19b3SKyle Evans kernel_name = kernel_name .. name_color .. 254fd2b19b3SKyle Evans choice .. color.default(); 255fd2b19b3SKyle Evans return color.highlight("K") .. "ernel: " .. 256fd2b19b3SKyle Evans kernel_name .. " (" .. idx .. " of " .. 257fd2b19b3SKyle Evans #all_choices .. ")"; 258088b4f5fSWarner Losh end, 2595d1e2f83SKyle Evans func = function(idx, choice, all_choices) 260fa4a2394SKyle Evans config.selectkernel(choice); 261088b4f5fSWarner Losh end, 262088b4f5fSWarner Losh alias = {"k", "K"} 263088b4f5fSWarner Losh }, 264088b4f5fSWarner Losh 265088b4f5fSWarner Losh -- boot options 266088b4f5fSWarner Losh { 267a7cf0562SKyle Evans entry_type = core.MENU_SUBMENU, 268088b4f5fSWarner Losh name = function() 269fd2b19b3SKyle Evans return "Boot " .. color.highlight("O") .. 270fd2b19b3SKyle Evans "ptions"; 271088b4f5fSWarner Losh end, 272088b4f5fSWarner Losh submenu = function() 273088b4f5fSWarner Losh return menu.boot_options; 274088b4f5fSWarner Losh end, 275088b4f5fSWarner Losh alias = {"o", "O"} 276d8757746SKyle Evans }, 277d8757746SKyle Evans }, 278088b4f5fSWarner Losh}; 279088b4f5fSWarner Losh 280ada26c4aSKyle Evans-- The first item in every carousel is always the default item. 281ada26c4aSKyle Evansfunction menu.getCarouselIndex(id) 282ada26c4aSKyle Evans local val = carousel_choices[id]; 283ada26c4aSKyle Evans if (val == nil) then 284ada26c4aSKyle Evans return 1; 285ada26c4aSKyle Evans end 286ada26c4aSKyle Evans return val; 287ada26c4aSKyle Evansend 288ada26c4aSKyle Evans 289ada26c4aSKyle Evansfunction menu.setCarouselIndex(id, idx) 290ada26c4aSKyle Evans carousel_choices[id] = idx; 291ada26c4aSKyle Evansend 292ada26c4aSKyle Evans 293088b4f5fSWarner Loshfunction menu.run(m) 294088b4f5fSWarner Losh 295088b4f5fSWarner Losh if (menu.skip()) then 296088b4f5fSWarner Losh core.autoboot(); 297088b4f5fSWarner Losh return false; 298088b4f5fSWarner Losh end 299088b4f5fSWarner Losh 300088b4f5fSWarner Losh if (m == nil) then 301088b4f5fSWarner Losh m = menu.welcome; 302088b4f5fSWarner Losh end 303088b4f5fSWarner Losh 304088b4f5fSWarner Losh -- redraw screen 305088b4f5fSWarner Losh screen.clear(); 306088b4f5fSWarner Losh screen.defcursor(); 307088b4f5fSWarner Losh local alias_table = drawer.drawscreen(m); 308088b4f5fSWarner Losh 3093a0a07d0SKyle Evans menu.autoboot(); 310088b4f5fSWarner Losh 311088b4f5fSWarner Losh cont = true; 31224a1bd54SKyle Evans while (cont) do 313abc4f7e7SKyle Evans local key = io.getchar(); 314088b4f5fSWarner Losh 315b458bf0dSKyle Evans -- Special key behaviors 3161504bce3SKyle Evans if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and 3171504bce3SKyle Evans (m ~= menu.welcome) then 3181f5696c7SKyle Evans break; 319fe672a15SKyle Evans elseif (key == core.KEY_ENTER) then 320b458bf0dSKyle Evans core.boot(); 321b458bf0dSKyle Evans -- Should not return 322abc4f7e7SKyle Evans end 323abc4f7e7SKyle Evans 324abc4f7e7SKyle Evans key = string.char(key) 325088b4f5fSWarner Losh -- check to see if key is an alias 326088b4f5fSWarner Losh local sel_entry = nil; 327088b4f5fSWarner Losh for k, v in pairs(alias_table) do 328088b4f5fSWarner Losh if (key == k) then 329088b4f5fSWarner Losh sel_entry = v; 330088b4f5fSWarner Losh end 331088b4f5fSWarner Losh end 332088b4f5fSWarner Losh 333088b4f5fSWarner Losh -- if we have an alias do the assigned action: 334088b4f5fSWarner Losh if (sel_entry ~= nil) then 335a7cf0562SKyle Evans if (sel_entry.entry_type == core.MENU_ENTRY) then 336088b4f5fSWarner Losh -- run function 337088b4f5fSWarner Losh sel_entry.func(); 338a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_CAROUSEL_ENTRY) then 339ada26c4aSKyle Evans -- carousel (rotating) functionality 340ada26c4aSKyle Evans local carid = sel_entry.carousel_id; 341ada26c4aSKyle Evans local caridx = menu.getCarouselIndex(carid); 342ada26c4aSKyle Evans local choices = sel_entry.items(); 343ada26c4aSKyle Evans 344aefcaa7eSKyle Evans if (#choices > 0) then 345ada26c4aSKyle Evans caridx = (caridx % #choices) + 1; 346ada26c4aSKyle Evans menu.setCarouselIndex(carid, caridx); 3475d1e2f83SKyle Evans sel_entry.func(caridx, choices[caridx], 34884f82e46SKyle Evans choices); 349aefcaa7eSKyle Evans end 350a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_SUBMENU) then 351088b4f5fSWarner Losh -- recurse 352088b4f5fSWarner Losh cont = menu.run(sel_entry.submenu()); 353a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_RETURN) then 354ef625845SKyle Evans -- allow entry to have a function/side effect 355ef625845SKyle Evans if (sel_entry.func ~= nil) then 356ef625845SKyle Evans sel_entry.func(); 357ef625845SKyle Evans end 358088b4f5fSWarner Losh -- break recurse 359088b4f5fSWarner Losh cont = false; 360088b4f5fSWarner Losh end 361088b4f5fSWarner Losh -- if we got an alias key the screen is out of date: 362088b4f5fSWarner Losh screen.clear(); 363088b4f5fSWarner Losh screen.defcursor(); 364088b4f5fSWarner Losh alias_table = drawer.drawscreen(m); 365088b4f5fSWarner Losh end 366088b4f5fSWarner Losh end 367088b4f5fSWarner Losh 368088b4f5fSWarner Losh if (m == menu.welcome) then 369088b4f5fSWarner Losh screen.defcursor(); 370088b4f5fSWarner Losh print("Exiting menu!"); 371fa4a2394SKyle Evans config.loadelf(); 372088b4f5fSWarner Losh return false; 373088b4f5fSWarner Losh end 374088b4f5fSWarner Losh 375088b4f5fSWarner Losh return true; 376088b4f5fSWarner Loshend 377088b4f5fSWarner Losh 378088b4f5fSWarner Loshfunction menu.skip() 379b140d14bSKyle Evans if (core.isSerialBoot()) then 380088b4f5fSWarner Losh return true; 381088b4f5fSWarner Losh end 382088b4f5fSWarner Losh local c = string.lower(loader.getenv("console") or ""); 38324a1bd54SKyle Evans if ((c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil) then 384088b4f5fSWarner Losh return true; 385088b4f5fSWarner Losh end 386088b4f5fSWarner Losh 387088b4f5fSWarner Losh c = string.lower(loader.getenv("beastie_disable") or ""); 388088b4f5fSWarner Losh print("beastie_disable", c); 389088b4f5fSWarner Losh return c == "yes"; 390088b4f5fSWarner Loshend 391088b4f5fSWarner Losh 392088b4f5fSWarner Loshfunction menu.autoboot() 39324a1bd54SKyle Evans if (menu.already_autoboot == true) then 394088b4f5fSWarner Losh return; 395088b4f5fSWarner Losh end 396088b4f5fSWarner Losh menu.already_autoboot = true; 397088b4f5fSWarner Losh 398088b4f5fSWarner Losh local ab = loader.getenv("autoboot_delay"); 399702b460dSKyle Evans if (ab ~= nil) and (ab:lower() == "no") then 400702b460dSKyle Evans return; 401702b460dSKyle Evans elseif (tonumber(ab) == -1) then 402088b4f5fSWarner Losh core.boot(); 403088b4f5fSWarner Losh end 404088b4f5fSWarner Losh ab = tonumber(ab) or 10; 405088b4f5fSWarner Losh 406088b4f5fSWarner Losh local x = loader.getenv("loader_menu_timeout_x") or 5; 407088b4f5fSWarner Losh local y = loader.getenv("loader_menu_timeout_y") or 22; 408088b4f5fSWarner Losh 409088b4f5fSWarner Losh local endtime = loader.time() + ab; 410088b4f5fSWarner Losh local time; 411088b4f5fSWarner Losh 412088b4f5fSWarner Losh repeat 413088b4f5fSWarner Losh time = endtime - loader.time(); 414088b4f5fSWarner Losh screen.setcursor(x, y); 41557099121SKyle Evans print("Autoboot in " .. time .. 41657099121SKyle Evans " seconds, hit [Enter] to boot" .. 41757099121SKyle Evans " or any other key to stop "); 418088b4f5fSWarner Losh screen.defcursor(); 41924a1bd54SKyle Evans if (io.ischar()) then 420088b4f5fSWarner Losh local ch = io.getchar(); 42124a1bd54SKyle Evans if (ch == core.KEY_ENTER) then 422088b4f5fSWarner Losh break; 423088b4f5fSWarner Losh else 424088b4f5fSWarner Losh -- erase autoboot msg 425088b4f5fSWarner Losh screen.setcursor(0, y); 426088b4f5fSWarner Losh print(" " 427088b4f5fSWarner Losh .. " "); 428088b4f5fSWarner Losh screen.defcursor(); 429088b4f5fSWarner Losh return; 430088b4f5fSWarner Losh end 431088b4f5fSWarner Losh end 432088b4f5fSWarner Losh 433088b4f5fSWarner Losh loader.delay(50000); 4341f5696c7SKyle Evans until time <= 0; 435088b4f5fSWarner Losh core.boot(); 436088b4f5fSWarner Losh 437088b4f5fSWarner Loshend 438088b4f5fSWarner Losh 439088b4f5fSWarner Loshfunction OnOff(str, b) 440088b4f5fSWarner Losh if (b) then 44157099121SKyle Evans return str .. color.escapef(color.GREEN) .. "On" .. 44257099121SKyle Evans color.escapef(color.WHITE); 443088b4f5fSWarner Losh else 44457099121SKyle Evans return str .. color.escapef(color.RED) .. "off" .. 44557099121SKyle Evans color.escapef(color.WHITE); 446088b4f5fSWarner Losh end 447088b4f5fSWarner Loshend 448088b4f5fSWarner Losh 44924a1bd54SKyle Evansreturn menu; 450