diff --git a/.gitignore b/.gitignore index c9f2f04..9de53ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ # This is released into the public domain. # No warranty is provided, implied or otherwise. -# leaving in preSH.tar.gz for anyone who's interested -# in how NOT to do compression code.tar code/data/app-claw/* work.tar @@ -32,7 +30,7 @@ laboratory/*/*/*/* inst.lua # Available as the respective release inst-gold.lua -com2/code.tar.bd +inst/code.tar.bd upldr.sh upldr-dev.sh upldr-gold.sh diff --git a/com2/bdivide.lua b/com2/bdivide.lua deleted file mode 100644 index 54b40a5..0000000 --- a/com2/bdivide.lua +++ /dev/null @@ -1,49 +0,0 @@ --- This is released into the public domain. --- No warranty is provided, implied or otherwise. - --- BDIVIDE r5 edition --- Algorithm simplified for smaller implementation and potentially better compression --- format: --- 0-127 for constants --- <128 + (length - 4)>, , --- Position is where in the window it was found, minus 1. --- windowSize must be the same between the encoder and decoder, --- and is the amount of data preserved after cropping. - -io.write("\x00") -- initiation character - -local blk = io.read("*a") -local windowSize = 0x10000 -local windowData = ("\x00"):rep(windowSize) - -local function crop(data) - windowData = (windowData .. data):sub(-windowSize) -end - -while blk ~= "" do - local bestData = blk:sub(1, 1) - local bestRes = bestData - for lm = 0, 127 do - local al = lm + 4 - local pfx = blk:sub(1, al) - if #pfx ~= al then - break - end - local p = windowData:find(pfx, 1, true) - if not p then - break - end - local pm = p - 1 - local thirdByte = pm % 256 - -- anti ']'-corruption helper - if thirdByte ~= 93 then - bestData = string.char(128 + lm, math.floor(pm / 256), thirdByte) - bestRes = pfx - end - end - -- ok, encode! - io.write(bestData) - crop(bestRes) - blk = blk:sub(#bestRes + 1) -end - diff --git a/com2/bundiv.lua b/com2/bundiv.lua deleted file mode 100644 index 3e75bb8..0000000 --- a/com2/bundiv.lua +++ /dev/null @@ -1,72 +0,0 @@ --- This is released into the public domain. XX --- No warranty is provided, implied or otherwise. XX -local sector = io.write -- XX --- XX --- BUNDIVIDE (r5 edition) reference implementation for integration XX --- Lines ending with XX are not included in the output. XX --- Lines that both start and end with -- are only for use in the output, XX --- and are thus not executed during any sanity-check procedure. XX --- XX -Cp,Ct,Cc,Cw="","","",("\x00"):rep(65536) --- High-level breakdown: XX --- CP is unescaper & TAR-sector-breakup. XX --- It'll only begin to input if at least 3 bytes are available, XX --- so you'll want to throw in 2 extra zeroes at the end of stream as done here. XX --- It uses Ct (input buffer) and Cp (output buffer). XX --- Ignore its second argument, as that's a lie, it's just there for a local. XX --- CD is the actual decompressor. It has the same quirk as CP, wanting two more bytes. XX --- It stores to Cc (compressed), and Cw (window). XX --- It uses Ca as the "first null" activation flag. XX --- It outputs that which goes to the window to CP also. XX --- And it also uses a fake local. XX -CP = function (d, b) - Ct = Ct .. d - while #Ct > 2 do - b = Ct:byte() - Ct = Ct:sub(2) - if b == 127 then - b = Ct:byte() - Ct = Ct:sub(2) - if b == 127 then - b = Ct:byte() + 254 - if b > 255 then - b = b - 256 - end - Ct = Ct:sub(2) - else - b = b + 127 - end - end - Cp = Cp .. string.char(b) - if #Cp == 512 then - sector(Cp) - Cp = "" - end - end -end --- XX -CD = function (d, b, p) - Cc = Cc .. d - while #Cc > 2 do - b = Cc:byte() - if not Ca then - Ca, b, Cc = b < 1, "", Cc:sub(2) - elseif b < 128 then - b, Cc = Cc:sub(1, 1), Cc:sub(2) - else - p = Cc:byte(2) * 256 + Cc:byte(3) + 1 - b, Cc = Cw:sub(p, p + b - 125), Cc:sub(4) - end - CP(b) - Cw = (Cw .. b):sub(-65536) - end -end --- XX -CD(io.read("*a")) -- XX ---D.remove("init-bdivide.lua")-- ---D.rename("init.lua","init-bdivide.lua")-- ---local Ch=D.open("init-bdivide.lua","rb")-- ---dieCB=function()D.close(Ch)D.remove("init-bdivide.lua")end-- ---while true do local t=D.read(Ch, 64)if not t then break end CD(t)end-- --- XX -CD("\x00\x00")CP("\x00\x00") diff --git a/com2/preproc.lua b/com2/preproc.lua deleted file mode 100644 index 98c8b8a..0000000 --- a/com2/preproc.lua +++ /dev/null @@ -1,20 +0,0 @@ --- PREPROC: preprocess input to be 7-bit --- This is released into the public domain. --- No warranty is provided, implied or otherwise. - -while true do - local c = io.read(1) - if not c then return end - local bc = c:byte() - if bc < 127 then - io.write(c) - else - if bc <= 253 then - -- 127(0) through 253(126) - io.write("\x7F" .. string.char(bc - 127)) - else - -- 254(0) through 255 (1) - io.write("\x7F\x7F" .. string.char(bc - 254)) - end - end -end diff --git a/heroes.lua b/heroes.lua deleted file mode 100644 index 4b65f66..0000000 --- a/heroes.lua +++ /dev/null @@ -1,27 +0,0 @@ --- This is released into the public domain. --- No warranty is provided, implied or otherwise. - --- arg is the size of the code.tar file -local arg = ... -os.execute("lua com2/preproc.lua < code.tar | lua com2/bdivide.lua > com2/code.tar.bd") -os.execute("cat insthead.lua") -print("sC=" .. math.ceil(tonumber(arg) / 512)) -local src = io.open("com2/bundiv.lua", "r") -while true do - local line = src:read() - if not line then - io.flush() - src:close() - return - end - local endix = line:sub(#line-1,#line) - if endix ~= "XX" then - if endix == "--" then - -- included - print(line:sub(3,#line-2)) - else - print(line) - end - end - -- XX means ignored. -end diff --git a/inst/bdivide/bga.lua b/inst/bdivide/bga.lua new file mode 100644 index 0000000..0ecde89 --- /dev/null +++ b/inst/bdivide/bga.lua @@ -0,0 +1,36 @@ +-- This is released into the public domain. +-- No warranty is provided, implied or otherwise. + +local bga = {} + +local str = io.read("*a") + +for i = 1, #str - 1 do + local bg = str:sub(i, i + 1) + bga[bg] = (bga[bg] or 0) + 1 +end + +local first = {} +local second = {} + +local mode = ... + +for k, v in pairs(bga) do + if mode == "combined" then + print(string.format("%08i: %02x%02x : %s", v, k:byte(1), k:byte(2), k)) + end + first[k:sub(1, 1)] = (first[k:sub(1, 1)] or 0) + v + second[k:sub(1, 1)] = (second[k:sub(1, 1)] or 0) + v +end + +for k, v in pairs(first) do + if mode == "first" then + print(string.format("%08i: %s", v, k)) + end +end + +for k, v in pairs(second) do + if mode == "second" then + print(string.format("%08i: %s", v, k)) + end +end diff --git a/inst/bdivide/compress.lua b/inst/bdivide/compress.lua new file mode 100644 index 0000000..b0a9f99 --- /dev/null +++ b/inst/bdivide/compress.lua @@ -0,0 +1,118 @@ +-- This is released into the public domain. +-- No warranty is provided, implied or otherwise. + +-- PREPROC (r9 edition): preprocess input to be 7-bit + +local +-- SHARED WITH DECOMPRESSION ENGINE +function p(x, y) + if x == 126 then + if y >= 32 then + return ({ + -- Before adding to this, check how installer size is changed. + "\x7E", "\x7F" + })[y - 31], 3 + end + return string.char(y), 3 + elseif x == 127 then + return string.char(128 + y), 3 + elseif x >= 32 then + return string.char(x), 2 + elseif x == 31 then + return "\n", 2 + elseif x == 30 then + return "\x00", 2 + end + return string.char(("enart"):byte(x % 5 + 1), ("ndtelh"):byte(math.floor(x / 5) + 1)), 2 +end + +local preprocParts = {} +local preprocMaxLen = 0 +for i = 0, 127 do + for j = 0, 127 do + local d, l = p(i, j) + if d then + preprocMaxLen = math.max(preprocMaxLen, #d) + l = l - 1 + if (not preprocParts[d]) or (#preprocParts[d] > l) then + if l == 2 then + preprocParts[d] = string.char(i, j) + else + preprocParts[d] = string.char(i) + end + end + end + end +end + +local function preproc(blk) + local out = "" + while blk ~= "" do + local len = math.min(preprocMaxLen, #blk) + while len > 0 do + local seg = blk:sub(1, len) + if preprocParts[seg] then + out = out .. preprocParts[seg] + blk = blk:sub(#seg + 1) + break + end + len = len - 1 + end + assert(len ~= 0) + end + return out +end + +-- BDIVIDE r5 edition +-- Algorithm simplified for smaller implementation and potentially better compression +-- format: +-- 0-127 for constants +-- <128 + (length - 4)>, , +-- Position is where in the window it was found, minus 1. +-- windowSize must be the same between the encoder and decoder, +-- and is the amount of data preserved after cropping. +local function bdivide(blk) + local out = "" + + local windowSize = 0x10000 + local windowData = ("\x00"):rep(windowSize) + + local function crop(data) + windowData = (windowData .. data):sub(-windowSize) + end + + while blk ~= "" do + local bestData = blk:sub(1, 1) + local bestRes = bestData + for lm = 0, 127 do + local al = lm + 4 + local pfx = blk:sub(1, al) + if #pfx ~= al then + break + end + local p = windowData:find(pfx, 1, true) + if not p then + break + end + local pm = p - 1 + local thirdByte = pm % 256 + -- anti ']'-corruption helper + if thirdByte ~= 93 then + bestData = string.char(128 + lm, math.floor(pm / 256), thirdByte) + bestRes = pfx + end + end + -- ok, encode! + out = out .. bestData + crop(bestRes) + blk = blk:sub(#bestRes + 1) + end + return out +end + +return function (data) + data = preproc(data) + io.stderr:write("---\n") + data = bdivide(data) + return data +end diff --git a/inst/bdivide/instdeco.lua b/inst/bdivide/instdeco.lua new file mode 100644 index 0000000..6ecdd6c --- /dev/null +++ b/inst/bdivide/instdeco.lua @@ -0,0 +1,85 @@ +-- This is released into the public domain. +-- No warranty is provided, implied or otherwise. + +-- BDIVIDE (r5 edition) and PREPROC (r9 edition) +-- decompression engine for installer + +-- cb: sector accumulator +-- ct: preproc accumulator +-- cc: bdivide accumulator +-- cw: bdivide window + +-- cp: function to submit to preproc +-- cd: function to submit to bdivide + +cb,ct,cc,cw="","","",("\x00"):rep(2^16) +-- High-level breakdown: +-- CP is unescaper & TAR-sector-breakup. +-- It'll only begin to input if at least 3 bytes are available, +-- so you'll want to throw in 2 extra zeroes at the end of stream as done here. +-- It uses Ct (input buffer) and Cp (output buffer). +-- Ignore its second argument, as that's a lie, it's just there for a local. +-- CD is the actual decompressor. It has the same quirk as CP, wanting two more bytes. +-- It stores to Cc (compressed), and Cw (window). +-- It outputs that which goes to the window to CP also. +-- And it also uses a fake local. + +-- SEE compress.lua FOR THIS FUNCTION +function p(x, y) + if x == 126 then + if y >= 32 then + return ({ + -- Before adding to this, check how installer size is changed. + "\x7E", "\x7F" + })[y - 31], 3 + end + return string.char(y), 3 + elseif x == 127 then + return string.char(128 + y), 3 + elseif x >= 32 then + return string.char(x), 2 + elseif x == 31 then + return "\n", 2 + elseif x == 30 then + return "\x00", 2 + end + return string.char(("enart"):byte(x % 5 + 1), ("ndtelh"):byte(math.floor(x / 5) + 1)), 2 +end + +function cp(d, b, a) + ct = ct .. d + while #ct > 1 do + b, a = p(ct:byte(), ct:byte(2)) + cb = cb .. b + ct = ct:sub(a) + if #cb > 511 then + M(cb:sub(1, 512)) + cb = cb:sub(513) + end + end +end + +function cd(d, b, p) + cc = cc .. d + while #cc > 2 do + b = cc:byte() + if b < 128 then + b, cc = cc:sub(1, 1), cc:sub(2) + else + p = cc:byte(2) * 256 + cc:byte(3) + 1 + b, cc = cw:sub(p, p + b - 125), cc:sub(4) + end + cp(b) + cw = (cw .. b):sub(-65536) + end +end + +-- quick & dirty integration with the existing stuff +function L(d) + if not d then + cd("\x00\x00")cp("\x00\x00") + else + cd(d) + end +end + diff --git a/inst/build.lua b/inst/build.lua new file mode 100644 index 0000000..7454a68 --- /dev/null +++ b/inst/build.lua @@ -0,0 +1,31 @@ +-- This is released into the public domain. +-- No warranty is provided, implied or otherwise. + +-- KittenOS NEO Installer Generator -- +local alg, tarName = ... + +local function read(fn) + local f = io.open(fn, "rb") + local d = f:read("*a") + f:close() + return d +end + +local tarData = read(tarName) +local tarSectors = math.floor(#tarData / 512) + +local instCode = "K=" .. tarSectors .. "\n" .. read(alg .. "/instdeco.lua") .. read("instbase.lua") +instCode = require("libs.lexcrunch")(instCode) +io.write(instCode) + +-- the \x00 is the indicator to start reading +io.write("--[[\x00") +io.stderr:write("compressing...\n") +local compressedData = require(alg .. ".compress")(tarData) +io.stderr:write("compression with " .. alg .. ": " .. #tarData .. " -> " .. #compressedData .. "\n") +-- Program the read-in state machine +compressedData = compressedData:gsub("\xFE", "\xFE\xFE") +compressedData = compressedData:gsub("]]", "]\xFE]") +io.write(compressedData) +io.write("]]") + diff --git a/inst/instbase.lua b/inst/instbase.lua new file mode 100644 index 0000000..2757e7b --- /dev/null +++ b/inst/instbase.lua @@ -0,0 +1,145 @@ +-- KOSNEO installer base +-- This is released into the public domain. +-- No warranty is provided, implied or otherwise. + +-- DECOMPRESSION ENGINE PRECEDES THIS CODE -- +-- NOTE: upper-case is reserved for this file, +-- lower-case is reserved for the decompression engine + +-- A: temporary + +-- B: computer +-- C: component + +-- D: additional temporary +-- E: read-in state machine + +-- F: current file: filename +-- H: remaining bytes to copy/skip +-- I: current file: handle (nil if not writing) + +-- J: sectors handled +-- K: sector count (injected during build) +-- L: compression engine data function (set by CE) +-- M: sector handler function (called by CE) + +-- O: current character for read-in state machine +-- P: file handle for selfread + +-- Q: octal decoding function + +-- X: screen address +-- Y: component: gpu +-- Z: component: filesystem +B = computer +C = component +assert(C, "To install, please copy as init.lua to a blank disk or a system to update, then remove all other disks and reboot.") + +X = C.list("screen", true)() +Y = C.list("gpu", true)() + +Z = C.proxy(B.getBootAddress()) + +Z.remove("init.neoi.lua") +Z.rename("init.lua","init.neoi.lua") +P = Z.open("init.neoi.lua","rb") + +F = "Starting..." +H = 0 + +if X and Y then + Y = C.proxy(Y) + Y.bind(X) + Y.setResolution(50, 5) + Y.setBackground(2^24-1) + Y.setForeground(0) + Y.fill(1, 1, 50, 5, "█") + Y.fill(1, 2, 50, 1, " ") + Y.set(2, 2, "KittenOS NEO Installer") +end + +function Q(A) + if A == "" then return 0 end + return Q(A:sub(1, -2)) * 8 + (A:byte(#A) - 48) +end + +J = 0 + +function M(n) + if H > 0 then + A = math.min(512, H) + H = H - A + if I then + Z.write(I, n:sub(1, A)) + if H <= 0 then + Z.close(I) + I = nil + end + end + else + F = n:sub(1, 100):gsub("\x00", "") + -- this sets up the reading/skipping of data + H = Q(n:sub(125, 135)) + if F:sub(1, 2) == "./" and F ~= "./" then + F = F:sub(3) + if F:sub(#F) == "/" then + Z.makeDirectory(F) + else + I = Z.open(F, "wb") + if H == 0 then + Z.close(I) + I = nil + end + end + end + end + -- UPDATE DISPLAY -- + J = J + 1 + if X and Y then + Y.fill(1, 2, 50, 1, " ") + Y.set(2, 2, "KittenOS NEO Installer : " .. F) + Y.fill(2, 4, 48, 1, "█") + Y.fill(2, 4, math.ceil(48 * J / K), 1, " ") + end + if J % 8 == 0 then + B.pullSignal(0.01) + end + if J == K then + Z.close(P) + Z.remove("init.neoi.lua") + B.shutdown(true) + end +end + +while true do + A = Z.read(P, 64) + if not A then + L() + -- IF WE GET HERE, + -- YOU BROKE SOMETHING! + A() + end + D = "" + for i = 1, #A do + -- Read-in state machine + O = A:sub(i, i) + if not E then + if O == "\x00" then + E = 0 + end + elseif E == 0 then + if O == "\xFE" then + E = 1 + else + D = D .. O + end + else + D = D .. O + E = 0 + end + end + L(D) +end + +-- COMPRESSED DATA FOLLOWS THIS CODE -- + diff --git a/com2/bonecrunch.lua b/inst/libs/lexcrunch.lua similarity index 77% rename from com2/bonecrunch.lua rename to inst/libs/lexcrunch.lua index ed49707..0d900d6 100644 --- a/com2/bonecrunch.lua +++ b/inst/libs/lexcrunch.lua @@ -1,13 +1,7 @@ -- This is released into the public domain. -- No warranty is provided, implied or otherwise. --- This program tries to crunch down the installer a bit further. --- Specific target in mind, it has no support for string escapes. --- It also does this: -for i = 1, 3 do - print(io.read()) -end - +-- This library helps in crunching down the installer a bit further. local sequences = { {"\n", " "}, {" ", " "}, @@ -77,12 +71,24 @@ local function pass(buffer) end return ob end -local op = io.read("*a") -while true do - local np = pass(op) - if np == op then - io.write(np) - return + +return function (op) + -- comment removal + while true do + local np = op:gsub("%-%-[^\n]*\n", " ") + np = np:gsub("%-%-[^\n]*$", "") + if np == op then + break + end + op = np end - op = np + -- stripping + while true do + local np = pass(op) + if np == op then + return np + end + op = np + end + return op end diff --git a/inst/uncompressed/compress.lua b/inst/uncompressed/compress.lua new file mode 100644 index 0000000..ff533ca --- /dev/null +++ b/inst/uncompressed/compress.lua @@ -0,0 +1,7 @@ +-- This is released into the public domain. +-- No warranty is provided, implied or otherwise. + +return function (b) + return b +end + diff --git a/inst/uncompressed/instdeco.lua b/inst/uncompressed/instdeco.lua new file mode 100644 index 0000000..ea9a07b --- /dev/null +++ b/inst/uncompressed/instdeco.lua @@ -0,0 +1,12 @@ +-- This is released into the public domain. +-- No warranty is provided, implied or otherwise. + +t = "" +function L(d) + t = t .. d + while #t >= 512 do + M(t:sub(1, 512)) + t = t:sub(513) + end +end + diff --git a/insthead.lua b/insthead.lua deleted file mode 100644 index b14fd94..0000000 --- a/insthead.lua +++ /dev/null @@ -1,97 +0,0 @@ --- KOSNEO inst. --- This is released into the public domain. --- No warranty is provided, implied or otherwise. -C, O, G, D = component, computer -assert(C, "To install, please copy as init.lua to a blank disk or a system to update, then remove all other disks and reboot.") - -sa = C.list("screen", true)() -if sa then - G = C.list("gpu", true)() - if G then - G = C.proxy(G) - G.bind(sa) - G.setForeground(0xFFFFFF) - G.setBackground(0x000000) - G.setResolution(50, 5) - G.setDepth(1) - G.fill(1, 1, 50, 5, " ") - G.setBackground(0xFFFFFF) - G.setForeground(0x000000) - G.fill(1, 2, 50, 1, " ") - G.set(2, 2, "KittenOS NEO Installer") - end -end - -D = C.proxy(O.getBootAddress()) - -tFN,tFSR,tW,tF="Starting...",0,0 - -function tO(oct) - local v = oct:byte(#oct) - 0x30 - if #oct > 1 then - return (tO(oct:sub(1, #oct - 1)) * 8) + v - end - return v -end -function tA(s) - if tW > 0 then - tW = tW - 1 - return - end - if tF then - local ta = math.min(512, tFSR) - D.write(tF, s:sub(1, ta)) - tFSR = tFSR - ta - if tFSR == 0 then - D.close(tF) - tF = nil - end - else - tFN = s:sub(1, 100):gsub("\x00", "") - local sz = tO(s:sub(125, 135)) - if tFN:sub(1, 5) ~= "code/" then - tW = math.ceil(sz / 512) - else - tFN = tFN:sub(6) - if tFN == "" then - return - end - if tFN:sub(#tFN) == "/" then - tW = math.ceil(sz / 512) - D.makeDirectory(tFN) - else - tF = D.open(tFN, "wb") - tFSR = sz - if tFSR == 0 then - D.close(tF) - tF = nil - end - end - end - end -end - -sN, sC = 0, 0 - -function sector(n) - tA(n) - sN = sN + 1 - if G then - local a = sN / sC - G.fill(1, 2, 50, 1, " ") - G.set(2, 2, "KittenOS NEO Installer : " .. tFN) - G.setForeground(0xFFFFFF) - G.setBackground(0x000000) - G.fill(2, 4, 48, 1, " ") - G.setBackground(0xFFFFFF) - G.setForeground(0x000000) - G.fill(2, 4, math.ceil(48 * a), 1, " ") - end - if sN % 8 == 0 then - O.pullSignal(0.05) - end - if sN == sC then - dieCB() - O.shutdown(true) - end -end diff --git a/laboratory/reset-i.sh b/laboratory/reset-i.sh index aed4030..740661b 100755 --- a/laboratory/reset-i.sh +++ b/laboratory/reset-i.sh @@ -7,5 +7,5 @@ cp ocemu.cfg.default ocemu.cfg && rm -rf c1-sda c1-sdb tmpfs mkdir c1-sda c1-sdb echo -n c1-sda > c1-eeprom/data.bin cd .. -./package.sh +./package.sh $1 cp inst.lua laboratory/c1-sda/init.lua diff --git a/mkucinst.lua b/mkucinst.lua deleted file mode 100644 index 7dbe047..0000000 --- a/mkucinst.lua +++ /dev/null @@ -1,28 +0,0 @@ --- This is released into the public domain. --- No warranty is provided, implied or otherwise. - -os.execute("tar -cf code.tar code") -os.execute("cat insthead.lua > inst.lua") -local f = io.open("inst.lua", "ab") - -local df = io.open("code.tar", "rb") -local sc = 0 -while true do - local d = df:read(512) - if not d then break end - sc = sc + 1 -end -df:close() -local df = io.open("code.tar", "rb") -f:write("dieCB = function () end") -f:write("sC = " .. sc .. "\n") -while true do - local d = df:read(512) - if d then - f:write(string.format("sector(%q)", d)) - else - break - end -end -df:close() -f:close() diff --git a/package.sh b/package.sh index fb89c28..e2017a7 100755 --- a/package.sh +++ b/package.sh @@ -9,15 +9,20 @@ lua claw/clawconv.lua code/data/app-claw/ < claw/code-claw.lua > /dev/null rm code.tar # Hey, look behind you, there's nothing to see here. # ... ok, are they seriously all named "Mann"? -tar --mtime=0 --owner=gray:0 --group=mann:0 -cf code.tar code +cd code +tar --mtime=0 --owner=gray:0 --group=mann:0 -cf ../code.tar . +cd .. # Solely for ensuring that a -gold.lua file can be checked before being pushed to repository. -echo -n "-- commit: " > inst.lua +echo -n "-- KOSNEO inst. " > inst.lua git status --porcelain=2 --branch | grep branch.oid >> inst.lua -lua heroes.lua `wc -c code.tar` | lua com2/bonecrunch.lua >> inst.lua -echo -n "--[[" >> inst.lua -cat com2/code.tar.bd >> inst.lua -echo -n "]]" >> inst.lua +echo "-- This is released into the public domain." >> inst.lua +echo "-- No warranty is provided, implied or otherwise." >> inst.lua + +# The Installer Creator +cd inst +lua build.lua $1 ../code.tar >> ../inst.lua +cd .. # Common Repository Setup Code ./package-repo.sh inst.lua diff --git a/preSH-Ancient-Est-2-10-2017.lua b/preSH-Ancient-Est-2-10-2017.lua deleted file mode 100644 index 99a8800..0000000 --- a/preSH-Ancient-Est-2-10-2017.lua +++ /dev/null @@ -1,609 +0,0 @@ --- KOSNEO inst. --- This is released into the public domain. --- No warranty is provided, implied or otherwise. - --- PADPADPADPADPADPADPADPAD - -local C, O, G, D = component, computer -local sAddr = C.list("screen", true)() -if sAddr then - G = C.list("gpu", true)() - if G then - G = C.proxy(G) - G.bind(sAddr) - G.setForeground(0xFFFFFF) - G.setBackground(0x000000) - G.setResolution(50, 5) - G.setDepth(1) - G.fill(1, 1, 50, 5, " ") - G.setBackground(0xFFFFFF) - G.setForeground(0x000000) - G.fill(1, 2, 50, 1, " ") - G.set(2, 2, "KittenOS NEO Installer") - end -end - -D = C.proxy(O.getBootAddress()) - -local file = nil -local fileName = "Starting..." -local fileSizeRm = 0 -local ws = 0 - -local convoct -convoct = function (oct) - local v = oct:byte(#oct) - 0x30 - if #oct > 1 then - return (convoct(oct:sub(1, #oct - 1)) * 8) + v - end - return v -end -local function sectorCore(sector) - if ws > 0 then - ws = ws - 1 - return - end - if file then - local takeaway = math.min(512, fileSizeRm) - D.write(file, sector:sub(1, takeaway)) - fileSizeRm = fileSizeRm - takeaway - if fileSizeRm == 0 then - D.close(file) - file = nil - end - else - local name = sector:sub(1, 100):gsub("\x00", "") - local sz = convoct(sector:sub(125, 135)) - if name:sub(1, 5) ~= "code/" then - ws = math.ceil(sz / 512) - else - if name:sub(#name, #name) == "/" then - ws = math.ceil(sz / 512) - D.makeDirectory(name:sub(6)) - else - fileName = name:sub(6) - file = D.open(fileName, "wb") - fileSizeRm = sz - if file then - if fileSizeRm == 0 then - D.close(file) - file = nil - end - end - end - end - end -end - -local dieCB = function () end - -local sectorNum = 0 -local sectorCount = 0 - -local function sector(n) - sectorCore(n) - sectorNum = sectorNum + 1 - if G then - local a = sectorNum / sectorCount - G.fill(1, 2, 50, 1, " ") - G.set(2, 2, "KittenOS NEO Installer : " .. fileName) - G.setForeground(0xFFFFFF) - G.setBackground(0x000000) - G.fill(2, 4, 48, 1, " ") - G.setBackground(0xFFFFFF) - G.setForeground(0x000000) - G.fill(2, 4, math.ceil(48 * a), 1, " ") - end - if sectorNum % 8 == 0 then - O.pullSignal(0.05) - end - if sectorNum == sectorCount then - dieCB() - O.shutdown(true) - end -end - -sectorCount = 260 -D.remove("init-symsear.lua") -D.rename("init.lua", "init-symsear.lua") -local instHandle = D.open("init-symsear.lua", "rb") -dieCB = function () - D.close(instHandle) - D.remove("init-symsear.lua") -end -local syms = {" ","s","e","t","a","i","\24","(","r",".","\ -","p","\"","o","c","m",", ","\1","l","n",")","d","u","\17","\9","x","-","\7","\6","\8","\4","\13","\2","\3","\5","g","\14","\21","\11"," then\ - ","1","w"," ","\12","\18","\22","f","F","y",",","\20","re","b","k"," = ","\23","return "," local ","\16","v"," if ","\ - ","\15","\19","\ - "," ","[","en","/","0","]","path","nction (","\ - ","se","h"," =","or","S","T","le","\ -local ",")\ -","= fu","on"," == ","ne",")\ - ","functio","\ - end\ -","D","{"," t","n ","oc","lo"," end\ - ","\0\0\0\0\0\0\0\0\0","un"," i","W","\0\0\0\0\0\0","fu","et"," end\ -","then ","nd","ni","A","ing"," tab","loca","etting",")\ - ","ct","C","P","}","\ - end\ -",")\ - ","onit","= ","end\ -","\0","I","Y"," do\ - ","return\ -","le.inser"," = func","= \"","al"," r"," e","in","he","nc"," e","j","donkonit","tion ()",") do\ - "," the","\ - ",")\ - ","ur","#","+","N","cursor",".inse",", v ","nction (w"," neo.req"," for "," then\ - ","\0\0\0\0\0\0\0","nd\ - ","()\ - ","neo.","ath","table","l ","do","2","3",":","H"," = nil\ - ","nd\ - e","hen\ - ","\7local ","indowCore",")\ - end\ -","d\") end\ -"," = false","if ","pairs(","dow","string\"","ti","O","uestAcces","nd\ - if ","icode."," if","v in ","pkg, pid","000","750\0000001","end\ - e","750\0000000"," else\ - ","window","end","00",".neo.sys.","neoux.tc","= {}\ - ","(window, ","5","=","E","R",") end\ - "," cursor","request","ode/app"," return e","\" the","equire("," "," then",".neo.pub.","hile true"," end"," en","\0\0","B","M"," ret","for ","in ipai"," true\ - ","close","code.sub","error(\"","return t","oroutine"," end\ - if","end\ - en","tion ","\", funct",":sub(","vailable"," end\ - "," l"," == \"","prima"," if type(","ryWindow","window.s"," end\ - ","L","X","~","on ("," in ipair"," for _, v"," for k","\0\0\0\0\0cod","lose()\ - "," = funct","rror(\"Exp","nsurePath","s.primary","primary","buildingS","unic"," "," re","surfaces","disallowe","ackground","neoux.","ccess","selectUnk"," end\ - "," = uni","\ - end\ -"," f","7","Z","z","for k","rue\ - end\ -","ode.len("," end\ -","lse\ - ",") end","end\ - "," fu",":sub(1, ","sub(1, 4)"," ","neo","the","if not "," th","tion","unknownA","end\ - ","[1] == \"","= unico","Acces","\ -end\ -\ -l","n\ - ","\") end\ -","de.len("," end","\" then\ - ","0\0000001","urface","nd\ -","()\ -","(surfaces"," if ","\0\0\0\0\0\0\0\0","unc","urn","\ - "," end\ -"," neoux","ction","\ - end\ - ","\ - ","neoux","\24\0\0\0\0\0\0\0\0","\ - end"," end\ -end\ -","\ -end\ -"," if "," err","s[1] == \"","unicode."," window"," if ","ocal fun","= false","\0\0\0\0\0\0\0000","\0\0\0\0\0\0\00000","code","_, v in i","()\ - ","d\ - ","f ev == \""," return",", bg, fg"," end"," neoux.","\0\0\0","w.close(","\ - if ev"," i"," if not ","if kc == ",")\ - end\ - ","indow","onkonit","00175","table.",", bg, fg)"," l"," end\ - ",") == \"","d\ -"," return ","rn","ca","q"," tabl"," error(\"","end\ - re"," in ","hen err","nd\ - en","nd\ - ","\ - end","turn ","x.neo.","ion ("," table","false","string","e.len(","d\ - "," re","1, unicod","cursorX ","local ","end\ -end\ -","cal","\" then e","nd\ - if k","ion","00644\00000"," end\ - ","\ -end"," window."," e","if not","== \"",", func"," neo.",", functi","\ - end\ -end"," r","end\ - ","ion (w)\ -","\ - end"," = false\ -"," ret","tu"," end\ - ","f ","unction","= nil\ -","th","n\ -","6","U","_","requir","eturn\ -"," funct","eturn tr","\ -\ -local"," table.","eques","rn ",")\ - r",".insert(","ode.",")\ - end","== ","\0\0\0\0\0\0\0c","n\ - ","\0\0\0\0\0","()\ - "," = nil","able.","n\ - "," = n","return","000644\0000","Access","able","etu","d\ - ","\ - if ","end\ - end","nction (p","ub(1, 4) "," return "," return","lse\ - ","abl","= uni","for k, ","\0\0\0\0\0\0\0\0c","cursorY","ble","bg, fg)\ - ","\ - e","ind","ret","tring\"","000000"," neo","pairs","then\ - ",")\ - ","le.inse","loc","\ - end","n error","\ -end\ -\ -","if s[1] =","lse\ - ","turn","ursor","function","neou","\0\0\0\0\0\0c","function ","\0000001","end\ - e","eo.","Access(\""," re"," lo","\ - e",")\ - end","urn ","\ - re"," end\ - e"," = f","\0\0\0\0","cal ","\0000000644\0","in ip","\ - en"," return",")\ - i","ction ","\ - end\ -","ode","equire(\"","r(\"Expect","ctio"," cursorY","if","%","4","<","G","\ -local f","\ - ret"," for ","d\ - if"," erro","true\ - end","ed\") end","hen ","nd\ - en","al ","on ","] then\ - ","string\")","for _, ","unicode.l","[1] == ","true\ - ","uestAc","nd\ -end\ -"," for k, "," if ev ","then\ - ","\ - en",")\ - en","do\ - ","e.ins",".primary"," true","coroutine","return\ - ","airs(",") end\ - ","nd\ -end\ -\ -","\ - return","window, ","end\ - e","end\ - end","750\0000","eturn t",", functio"," e","d\") end","en\ -","ocal","icode.len","e\ - ","n\ - ","w.close()"," uni","sub(","n ipairs("," for ","end\ - ","ion ()","end\ - en","quest","cursorY ","eturn","unicode.s","x.neo.pub"," = neo","hen\ - ","then\ -","string\") ","in ipa"," retur","indowCor"," re","750\00000"," do\ - ",")\ - if "," then ret","\") end"," en","n\ - ","ipairs"," then err","d\ - en","= f"," local",".neo.","\24\0\0\0\0\0\0\0","func","()\ - ",")\ - en","curs","\ - loca","ode/apps","nd\ - if "," i"," = neo.r","kg, pid, ","\ - i","win","code.sub(","require","wind"," else\ - ","close()"," end\ -e","\ -\ -local "," then re","\ - e",".request","wnAvailab","tion (","\ - local ","error(","\0000001750\0","n\ - ","d\ - "," ","uestA","reques","end\ -end\ -\ -","ion ()\ -"," curso","then\ - ","0001750","surfac",".close("," function","= neo.","if type("," loc","d\ - e","oroutine."," do\ - "," else\ - ","tion ()\ - ",", v in ","window.","neo.re","0000","\000000","\ - end\ - ","ipairs("," ret","\"x.neo.pu","error","\ - i","\ - end","()\ - ","= nil\ - ","nsert(","n erro","rror(\"","nil\ - ","cursorX ="," do\ - "," for","turn f","en\ - "," table.","\ - ","\") end\ - ","\") end\ - ",".close()\ -","\ - re","d\ - e","\ - end\ - ","ownAvaila","000644\00000"," false\ - ","\ - re","false\ -","ion ()\ - ",")\ - e","urn end\ -",")\ - if","x.neo.sys","indow, ","then\ - ",")\ - if t","cti","ion ","ion (w","\" then"," = nil\ -","then","e\" then\ -"," if","on (w)\ - ",") do\ - "," en","tAccess(\"","surePath"," end\ -end","\ - end\ - ","e.inse"," table.i"," local","oca","n (","0 then\ - ",") end\ -"," loc","se\ - ","do\ - ","nd\ - end\ -"," then e","0000644\0","ion ()\ - ","ocal ","end\ - if ","e\ - "," then\ -"," local","icode.le","\" then "," ==","] == \"","eoux","ndow","\0\0\0\0\0c","nownAvail"," functi","0\000000000","eoux.tc","hen error"," = neo.","table.ins"," window","(window","d\ - if ","\ - if ","\ - local","end\ - e","nd\ -end","insert("," local ","k, v i","surface","eturn ","\ -loc","sub(1, ","end\ - if ","io","!","$","&","'","*","8","9",";",">","?","@","J","K","Q","V","\\","^","|","","","","","","","","","","","","","","","","","","","",} -local bytBuf = "" -local bitBuf = "" -local function getByte() - if bytBuf == "" then - bytBuf = D.read(instHandle, 64) - end - local r = bytBuf:byte() - bytBuf = bytBuf:sub(2) - return r -end -while true do - if getByte() == 0 then break end -end -local function pb(c, p) if c % (p * 2) ~= c % p then bitBuf = bitBuf .. "1" else bitBuf = bitBuf .. "0" end end -local stn = 0 -local function getBit() - if bitBuf == "" then - local c = getByte() - c = (c - stn) % 256 stn = stn + 3 - pb(c, 1) - pb(c, 2) - pb(c, 4) - pb(c, 8) - pb(c, 16) - pb(c, 32) - pb(c, 64) - pb(c, 128) - end - local bit = bitBuf:sub(1, 1) == "1" - bitBuf = bitBuf:sub(2) - return bit -end -local buf = "" -local mode = false -local bc2 = 10 -while true do - local bc = getBit() - local v = 0 - if bc then bc = bc2 v = 64 else bc = 6 end - for bit = 0, bc - 1 do - if getBit() then v = v + (2 ^ bit) end - end - buf = buf .. syms[v] - if mode then - while #buf >= 512 do - sector(buf:sub(1, 512)) - buf = buf:sub(513) - end - else - if #buf == 27939 then - stn = 0 - bc2 = 11 - bitBuf = "" - syms = {} - while #buf > 0 do - local len = buf:byte() - if len > 127 then error("symlen") end - buf = buf:sub(2) - local ch = buf:sub(1, len) - buf = buf:sub(len + 1) - table.insert(syms, ch) - end - mode = true - end - end -end ---[[%]-Er=´ZENϯpᄉƈӦ4.6y3bHMvk -p h 3/U-3PMn4;Fag歞y̐xg- {.w1`&RO?!1-y Ol!m<;.@hPb!dd{R8hũr@1F -BSy]S -nn9ZKá_6" ¤qd2YZk(b f_u}̈́1ؠSldx3O -{=|"9s'`%@*QR?\.>e yv>Ã29·( -W/5sЌns'cFnňrO/DIj,yBտ듗 AUЁ^\\ǎ70x1"y g+/I`ޙ.:Gm!ueG4T.pX*Y(1ڋkyaox -rԤ-*λ*B?AiRi6;[q,H#U(;]FSv])]֍pgr/i4(TꕄW+!O+T.R9bނ`?Ɲʏ 0E"e/\&P50SUk6Im0q-kEܷ7~٣[Ҭ7K~q=-fڀ?8 mf*Zq3MISMSnSjwpr("+niU]UMN۝[_n#-<oƨ:)}3lhUY.^챟~ ?L҅h"bY+ҕޚ2 ] ||` ]]#M[nJb6@MyHijkZh:o`ǛIY=0J -XdPm߱ - 3F, ~ ;BTI((lۑh9*j4eY\ť&To=;h(+-<7yVg&Xl6U: )+L07PRCORY.EWx0?_tK$>78 |bB,.u{AILNxwu1=B Zm!a+}/cK,Emqso]cBԖ Tdw'4[OI%FúmLzf]>tKCJ8`~rUvQ]Y٬765*뜓{<Ң0  -e !$sq;tkȌXk%aˍQvAI/&?'?qט>~%CT_W*%\&,m[/lÔso"-#Y>FF]@)xA؍5Tz/hlϿ9"KL ;$hoj?#v\=0<0ec+?nVރIl7nqhm6g?׻*1|+mkFM -I^!z:j{3ѱpƺ:/V\6zT?€Ӝ//eLCg ԥ'2 W#{5Ɨew\(m_%I!1b04y9"26<"Vŵb}pV"Dq-S .߮:cۈL<=~!'8R;TZJNo%UG G[#rKyf׬  ˢ`ڃ`)iRFXCMȢ6@wCWqC,#hiюLKYE@KnZh)91ҵ(dzʸ:fU&9 r*2bg>h~Mtaɠ)\Ky@9`E*05&Jj2p -#iM-i8 -2)%2mBMCƆJ^m~D@~ $4=J$ b2 !n x!f>21a_=[易G<0ZB?~V>^ OFL |睥>ýB[5T^=G\MUMzmdҦ||ք΃ʔgx`յlNc,{80':9 N٘Nk޸8nYP]\`EjCus| 1G)x*wA=pX7`>߰ )>p}gUDE2$k߬!MD -pV!~%kڴ6(ސ(>£Ms -*i %x?c_C Q2XwK=ɀ}k/1maRoD3 -b4٢$E#IJ2O۫5rW~4,;&2ZV(]VpGZ -ۛsr'yEvLtl-=5хfqjsu0(Z(;-arYCrײDNdc^|L<u_yxn[KAxG9 ǡg\ָvfk̼r[ .chJ`|( mg*tI?}CM:$tzI]{vZ\`7-*λaݯ?٥ISK9!i*Z CE4aUylcz|GQ){o7,n=8a4jÏvU%L 0שXDzK)FBi[=eP=F%kB=kǨ:e24Xƅ T?9*78 9KG 0.uW'`H&յ?9 ϕ]}/qNk#ryar(|^ə[Cꊖ3z-ܿKW:E;EV-i&#+?H=q -(ϓR|rpԌu 4*i6~\8mcw/Z»ԗnr]+:qDHSAy0f( -kQ&ל g @fWٻ2ke-(s|c *>`Kў6P{ 'ǛhtxIFӇˀaplg##Ę8=uAXr/ڸS`&{:7@v Qt!%(u-qs~M0Igsٟ<sz58ϼք܉~Tr߅$L]XG1\՛! hpOb*]o7b[%M:IXڊZ++|v,=[F2 1lzP j2@bYC_‡s `߳Ab'L9'iM\n[elQɗN TҺ}d!bŹ1-d vW(.(.S:J](sbtՅS^sFQ#V$#A/8dA'˫瀄˖cC.ӳ x$/'ewUs̫>;]L.uŢE*f.CUDM?fZ^\\jI8 )",SdB{T@Ǣ -L5oE:)2:+h+ԽxG^tHUڎэG5UΞlJ aſֽJIY/5:$E\.S/L?p4u>NĈƱ'+cǖ ZO<⤝VX -jlxRH}%V-Zt^^2o7/F!?k㤩rsZnz?9 }掔:c{$/B%?{Q;r 敂 ^:N/kaH8r79`;9 KXUXb|/ބYǏq,I!&a< O]\F$c0:B"HA&) u)nҴ)~@՝wvdS峧ru{Ns=L£-N"ΐȮǢ[bRJmMQ ECTDz"XrA_ }?6gN$!/HU:< ]!{|g'B - J~g#?|Rf-`pEiKd;UjZoUvz(冈W(({C-T+ Vn{S,bB -lSR5CEkoRc\WväS{̟t^Ir3L qi;,1Lxk 37nI -yW#ew/̯i f%OXJ]إ8VP`!>_">T+!y=?DJL{`4xk wq/ - Ҥڙ<;0t+a/#}q{Ww-Kdž + pk]ԜćO_ BP{v,nݤ( d剚r\Z30W2XF1zVNdqmƞZ#*bo:xhGj ΔTu "TI a|hZKy4|E K\ήzYl7BqJC81 }Y;$ ż]a;W_;Zb3т2o{*-2hI`ÒEkH5iDS+Y&QB-ґ:za -^<|OES< 9^'^6Њ g%Xˮ 7|+$"eK[OhSY iiI _ɡ*^;,.BWtQ$ӑ7^@_*}z@koˢ]uD+It4_ ' -$@"a)֙]x" 4;>nSNYG)IwcZt79 VqzdK R)]~%rEl j?xvxJL&^d̛@ks u|#⌢hC -|a w؅jB_o -Wi}c>6Uc/ й;eMA}|H3_k|kɯ/grb]Ï)?>gS"IKL~ϲ> C8 V+vscA('.F=p|p;> s޲~ja|g؝%v~Ƅot;iDHNvF gqo㌆8jQd-~JCe-ɢԑTM7r>Ą.Z$H*F -cߘT1ҋ+Fn$& wo8#@NrͰV$$9?_F -e! iz}%n>V7 'L '+.Θ?(4CuEi|wJo=ڊ9}CjǍ ZMbHi>ɋ׶z㳵^;⣥\p꣤ b1Q*aM) ĚJĊ~}N՞Bv_—Cq^BPhƤĉ:qx`6ӥP;aM]V6iLѢnZ dtziY'"dװN.XN ) h jsB]#iTSrfi/ORDYcgmdc5r6p&uAv>((fQYW2uI.Ai+o%Z@΃Yr1Bo~csD8xxME#3I0B5!V"Y@H5Mp+!Y)F/#s&#=}Fds[-~f*{z-ӗ́ͬ~U,@F{E3{<0/fao3JCdvpmZ 5E~ZQ~1>mt:ij4n|@:ŷ(S.DL*'xs-W끄W$Vʭ)?OqB" k,VF -|伻04Qp '$Wf;P.}{¨Ur$$7I.D:{{ -c1*Zց}XꨑGAD :%3ufL>y4K3tm - e:ϣ!b.r6+ev[R{ 8C::)%#CןOBq$Y]|Q)`\!/qJ='<#{Ht׭c^^|WTzpUJgWa-GO.A \ -vz!@/ VHb]|l.c_FIsp3pЇ<$㜕z4p809uܾ񫤍(2\$Y2=2~."5L&IMMBE 1viz~ 6ISC.Ccuh1R&84%P)m^[]3sR>nQ:7PHv~r~&ң'}%:Ϻ@DhkeJlj)fSE6dg06ĺ+TT%QJWehEeࠣ ҉D)rEݾT-rΐRp9pz1{ -6$f.e邬y4^m\oUF?=t̃ij<{UGC )W߉h℣9|2ɲaP+QPFV[^Hn_W>cKT%0S|ZڀSg>+p\JųVUFHGu-/p8 -[MKB11yQ5?TbRub -rbj%)T?7gA$wpF --U8,5XJciII*,WPk1EemY\帳~ԟTو( M%E7M-X y$q % $]몋ŝBJ$RQkmvM!k|G3k_""H EBʈ!6*F۠EwA+u3EΙg][$ԕJ::HbY"T:Y(-F8Z9Οx3NY" C,x&3 =+Ԉ["t0sDQ,kHq'TB;c8g)E {d֓!£,#M`^GS6ra&S!2%a0omo3w |[7Qs[2V '# -֠ǰYiI- 6Sټގ̪ArG]k+^e5@=>CM[6R0:2eϒ&Š5 鳦}O- [G.W$\+C-_ -bO{&3?H ~Sj|b5fril=*u7rP>x:r?Iʥ_.e1hP {FBC,{7Lj|WiH,j1t #9&6a~S=!^եhj&m.3OE@U7:ݸ59?rx/ze2Y\(H 1VmiѪ:\2:Mc4f$d(q/U:ig35 -QمH3Hqw dRm4ҖJ>Ʃ%;s -Iz\t`^BwP0)xPgjBoC~Cc8p,=`:E Юwܬv?q< -*-g[ʤ݂JqF(+6%S LHD{^HeQ'u ?xI܊ϏuÈc˱h:zaYݍ&FBxp( =<9lˍYZxQ #/2p?SLe(t/]Q{PC}uQr3.?YVR)%r*6(=L:z*i.d<ޱMq$Ԥ2P@ST -N)=  FGV-l-6O9^g4(b8]sf 4~~T˼d[ X{v(TKYHr?\즹'@BS(X@v”>>Ք+\&z\l϶O3q] =,l16"spˢoq8`a氩?CVn\VqapJIc&E㏉,%ec Ef8bG_^cjnO ;AzpGJ/r4˻g6sG=(. 2YD@'8W_ DQ_UpoթBJJ#dB-m6D@>Hh4w&}5Z!<)YS0IzSrFFr-pE,4e9cnhLd=dG8?WY4.jD9' oE~IOJA޾}/,T^i+>ȅG^`U _de@2ӮWIkkABCkXbr|M+(!tCd+>;Dm۳] N^\w]]SH05|+2,漪oW ?-Ϗq[h^@=AL4^\^dcEVӇcUS#&}δ60PuIV^\mB!DJe@FP+i$smcOz |^ΰU3V}NZ#$/^%topVV̞@ovڟ'^r#j&)Z/=Xy잍48PJr8mEy? ө}SŨ:͐J% -c$B !o>duN,˸쿡+[,ƪn1s9OeQi]2~q1{Tʥ(J60,:z~IY$![ydPmeV ,`&eU0=N߆/7X^GϭB*/, Łbvα4= -ux\k7(oa|x~;Xܢc%ܡ9?;N8}-YVkS5x, /SV4D;9A\-0;kvqpt ͰK򿲭s#C,>G[ɂ:Tg'SG w;_7*%$%iL?V^L5ʇj5=ҧiSt}@>ܑKu}04.M(nK[s|M-N;03\VښRbc98gd nfu==9TȵsvWr@nw^Wa|/:&qfg1M'84DM`n_j?e2kim"/)<릈CX`1g N'mH \rn/8xfM^͕NUZ_P.{ !I@ִmR05< ]}A9\>/DS+'<-F=ͦKNJkM^;W2T A\͢in~!l81?L -764/)Q\p[~?H90tq6əG5̐0G~Y|gT9#|Dz 4z&| B)idshxKDtfjݿ>&xz^ Mwe$E)6><h*YIG{0Q"-Ed?>Gʾ9>˒b[}xDN 4! n.}+ -UC2ńߖrOnP}$tz{4w>f%];qRz]+Ү,?W{ebsR՛Sh{З(@];+xo~^O^yBqknlLfS$X;u\%ҺvBagatb5FV1¿pnMx$9ar9yW`?DF<HoTv,;uB=28E;gHReBbYhsq5uSl_›J乡׊`_+p7R[8ܢIFՀ<^C~-0j^2SmՓ3 %Bo/49U#BZ$B> Kt:HS[dgPff]_baAec+P?`r̽4l, $z$G_0% (Ho;⾌BvŹnJ&[EN^Z/D?] 5r|Q&.G3]-8_+Ү,?WxH@W 32n_@3 -a)T[}}+y6{ ,'P6{r֞l_Gc,{r.xiO>ɘp+67+VOwVoBh%+y2~^<493yBd?SEbz[W'Cq(J߄|:'OTf,*Pp{]s؋샍Y)axaI2}YM8!͏ptB_ -Ք-23{}B}DsX~f5\cķ~:v=6yod0. 80 %\LI0&:i1|9[VlP㉍ۀEj̉jq %T 3w3`hvNvwm3-&Qk!It|z -U:h1*kK^z|p_(Vd$$Y Ÿ5J -+5 qhu5+_R3 -R7<zݟIƩLQ2b%Y͵`z{p~ ϺN~g1kc;bHcEJwy eDʁ.*8[34Y+,vymoa~m m?X;aeed*[䆇[v~S)wZy"eӊvJ-u {K?;m)ncq -!X{Έ*q|Bo -8!jA:lHzy*KD-b&8gځ=×Xаt󟔳ÂRͱعZr 7X@uZ=0+*ȣMОWJ13↷osUWC Wcڙ-ؓٳ`T){PIL+1op4GM`6pkfwZcwp'ЋK .@ž"U$ڧ 'vAZ^r24 $Ga}ycG0X_m|@z 1#Ȥt]-X4L+y qI<1[1-J359'xa\shhh1gcR3co)YQtNpVvA9m}]27f\ ,eΐi^^z^'=ɪ(еStSQF2] -)b˨sҐ)KY[8?H)ORJqI]$g՗p {fQ-b2 Jo ](a8F"~:XBs-]:}*<ђ=?žgzl j"sZeE\Z?/#煲|Ia+^;p9Rb1r$u&Qm6g?)`njXqK|=$+31P8=A{Pf M~~=NŽ:3JSI|QXcaccwwsP# mcGtWBZϘ_j`D ;P"A4!?^3Qq{D$c#@X|qkь" Hq%o8®]^R{[;+ɫ_JC!Wx}| o|)cp]S|NjG8!XUVSimMB~@~ ~ΡM[u llhEogXdo9OzSk-:0 m.1‡+g;9mypz!։U"5\Ao9s68BS^R3C"2qy^u [+g_7!Z'Wea^1y H #tsL*DQƵ9@A~ ]wn+N$h*\ǢԷ'ɀ:%{MTvMW/h2(oGi$5x&GQvYӈ~ ^YXY۝snm#( Isx71=nڣ"7N K${']X/r07Q<&/uX4=7r}_2ܚ2/؉%)/wzJ -αqHrӛ8P(_+-'-;;dW8J+8aZĹ8p.znђ՛!Ʀ+.)<KNzYJ3 -0:M([/a 4lH^b^l]`UKkNl{7)6oɜxЧ=W]|ِm9ESCPVftƴ~_"MTf~zo5YPj+֟HۘrurgR8 ,E%88?K+ `=fI[ctX=3+ޕf -Ū)J S  -j>NJeO<*Fa2P~*ls+ACS,`^NUQ.PgR| #a:'{ P'̙J`Vl/FEX20R"6$)a-:?zBWѵuim'#-9ž+7&wOʁtߢqd vHϕ *< 0uJid/Y\!Z5VWGɍYD_,fOQ݅,K&\vP 34KG0) -uJ}.wNc]>Z3f3i5h5iuj/c X@ T5 -z Z-jB"F/:U}B -KȆ1tuJqى>u} uD@c #[ 9S HCYuCxcz{;tHKxU̷^UorYt`!Tx!䈎-(aQJZbmEw]x8y|5zB.Ǭ]""İTcmCsB}z;+Ѽ9l'Kq G^TZv['q"I8|0=Nͦi9I pst.N:hꮪ"5RC`<˂mϞ>ۭ]Be`6X1&H+_!ܬRײzxFf:RffЍ[|t,1픋Lo[1?HC7$)M=0{-l)0ҞJ|B I cpEoR Ѵ$ɼ91ΐ\WY8 oR[ c=iM{)E}2dZIDCpkVؚ}pkjkO۱ݹMLqd.YpHĨg$1m-.?)*i1sm :P% ZACȪ0h7}Fr^y1C'o.v ɴ&%LE9V("~N=cYBAHrXydD:{-G?Gy:.Ϡ4f:腺Q]ch[ |v(+r@=I9Ąu@}0y˦C߂B~Pff&(u0̽Xm'<!?5 ~^z' P@w駶Q1:LL`|gp/CTanT%%Զ2IWP Kd S 7grMy#r5L3JFJ0Y2я4%k}Q<&-MŒaH -Qx.D p> HTt'.Y]'*wgE B;aUjф ٥t&]wzzլL15?=.3ߛ}3@=>3PpZVclT&̖0 $*{Bҡ٪ -M{THm Ņ7TD,h ,bqƌϋ6X&k -tF{{EXp^C9+LG)ˇs*(y%:qHʯ~;LgePhA4\cY@vJټ]ammMpǜRE..OeE3/M!,6WƁSSiT[y-6l@ϲK)y[h@"8'k *ⴏI& " %5gCHiݵ({ۧ]>c4}\ Icb@ G AQ7V$ 1YWHnxO_VL/\!sem3(ڪ J!owI;N"t_G# :$KǚqmoCƵK֒`]柢Hry,{[e՟Ψڿw*[p2A.7  zT9m`>[IQg `gqu܍Ѵ$9$=4Eʗ`@vO|TPP[l|+|a$ -/A4wV/fye\}d)<L>߃Ȗa:3yGf"%kk .9$.u?<+8jsw6mRI[`ƣfvjXY7, v!]ݕh@9a=f9x^Bg"z]J94[,ӶNsֱ] - ͖,2O YÜĨriQ.JGƧܛ,%%)J:B`0Xa.Q{qZ5ɭMCL1Dj g!W?8Z"(moSAq,o~VJXcHУ}-9ǯ=!ܑp|B{X0*t6fWr6ҥZL$O#5kP(`a*su[VPR2`u:컓>3_ڈb;4Y U4 -z~􎷗Ч|H~a;2IFtT΢ocޞBYā2ޖ͛ң&5YZINIF "w2,&(Ay$TJΠ*-:7(kh5;|;ng -Ot?hM i4ӑ-/jB)S&sEyK˨c?Q"mvLEK*-^{!&BV$\;tpbPfOlh\^C.hUSUghKWr;w 7Ta~B-o骛L4)(4'x(zr! xD X-5-=Q+?9|n W^*rv6@{bcy穋5yI@/ YiCt?6Np4\::)28GH'тܻ+fBݜôcsn'Ga }$j 7'QXHk j 4:[Χ_PjU>'#n7;@\-Ԣ$2X]#B $2qP:UilTS$&jGjᢳQ܊G@ivh^rM9i#q3KBG1ڽ,;_Y&ctٲL g-o}Lv9vt<Ϡf9 =odUN`-æt||mmE J>5abZ_mbNKA/zՎ)o^ W1ϮP]VT^a"z-oy7 ˊj_l7M&M&Q.N ^Ӵo_M;@ /]R~7B8QW}/߆/&%/7.LixXL䦺MN`&p`{`5W4!)#M O!aAt~6bA#3!%U 2&m -buGAO[,4;+h9xl*6t_J pѴWlA1MP)G/R,]ID܃~yF4 1T^2npJ2{?B5Y߿,8 g]e|_oXOYЇDa1 -.2ZA"6pv ',}ぴ*h1 `VčmK&w9g6_K&fjɺ7CY3SpgfƙcAA葈Z^5Dmk~~o R~^+'H{Bco~c5GT&,芌Y[zRRjpj/ :tF £VBHfS Lf0eUA]2۾;e|KUXemC}=L{ńWYei -%;ٸI -aU1м" _UA~/#vUmzdb$B~%yrH"-tXEsھ妈&@Yg6ODX?L& qʕZEѤĀ*v\׺Sm#h. ڽ є?o{}ֺH5QW}X11v]=>9_OZR6Z͈lº -lD+Ƿ4iB^f0)+;/O!M1 @"Ϗ2HaLڕ@zk\7Oؗ6l_年ua4DTl̟qSxrhI@vP1}!!VHCep|rteoԃ*jSv๩TFƶ777gPmߔiΩx:3҅~to0Yܓ,=[@h{{/(~#W/\Dˍ2T WR#`rG_)W哠gҚ v:YwuLߗ u2<7D06K `"u7yF)ķ L&B/KaN4+3 -^vqpt Ͱ׹i\v━̐+6QB04l-fLڡT7*Ij767{^QLK(/qj~ĝ }Bu,0pp˫ӌjUPu?4!f#x0SM1~~sqoErIr[0&ŜJh+@%ȩ)N9D-?jD4|!^ ҫ#r5x`Ihy9Zh<\{'V gA;ݭJiز)i8Aj3Alcdo~>~0ŃQ@mə=l;5\-hJs@8 nE{Phܩ'q"Jp~ZM$7T@:Z[QM4ЉXɁoʾ]N߾h[t9T1#Е^Uֿ5 =jt1uPa"7Yү:˸i_\TV쎑P;hDžԧ"Wӷ7B.rE2;G -<ǜZ1ܢE{M=_tɮH)ǛNXhybCD\]84Ռbd&*$2OBY`~ RvQ)9?4$GLωFUA\ebs->wWvo.ܤr!RNp L{KTot3Ubi;%%NSƔf5;CiГ+q%c'3 9#`n$|&:%nBIpw]V egMd.&bU0u6BB -L'n w7"ak)-EL">}c -ޗ3I=sն狝 A*uDoytPVyX~|mJ -64&%o^Q`!~e6M- -'*&%KJ/ݴy p䐊[_!,a1'M]GcC=pq|F[d JiKO*Q%>%/QdY; -bgr<6/UڡB7]2@ߜ2E#m!$.&E7Jq9ZvRS?bZΒ29wg:>ُڦb $6=2*;?G,wnaX&7N aU6L+Ò,`yOzVf( 1B!!a^uSU`Ƞr@[ $TPq41\(V#*!A5V[7jhCu )="z2"sC z?>V:d̿/w|tT6iWgRmr(.3A@ZP{U=5ak'1@9SF{[!}fcxx+.Z!"%h,'B E'1v )c;{StYrF^r=Dnᆉ~İc,^indk]>Ug}8(0αKZ[hZ6;1xS(T،]9;6oAhR!ƒF/iv'#r ?2Ϩg\A(Y5(z.HCC\Ej.2> Hv' -\n"jRPͩ|վQg_FLLX=:|*O00PƑPv(6|Ž̶7AMȃV4qԒ!z JZf:crHW=_Z)Oaytvwũ]#eeWq)QZ'v ->=~ Ub%_ltxpzdM_o/&(|VmV#mIgfy#AK*CmaN7{ #-Dz=^٧Za`&tӘ?r(հr)7\@ Ssy^&Z:XL |oS71AZ"mOsr2G6[WXu"vt̯x;QR%cxln5] -?:Z4߃Y= -Z6ޟ)J!2$A|8ȴtrauyd#u ?T{NP0YT9 DYNhg1\M=7@} s.&jbd$ƇFԟI@%5gۦ@Xp+"禲EḒVB_,Uphڇ 4$dhX>/# c$4@Ir eA>03ڏ\>cKeluws+>w˙=2%E JJ<ֵF3jL[qSq_{N‰jɠlN!qCy@ԥ׵VniTclص9W cha(jV9SpRa -?J  NS# [ֻZ[S[sC=!R[%tv`f{v+2Ϡ?/nUNd>wS.,~B u (;?45%d;UU6=C ng}0΢}H@/}@$hr)}$ejň&`2YwSE_3IT7^qgAirdّb{1^{ͦ+MgRbw5z(' 䞎`:LACx\Z)`hYӖr =éH;؊$cxؐ,% O\If g/)>JiAG8Dtӹ#LqJ`@dt{yci t{FY -xp/= |Vj&y5!,HE-US^Yr[fZE2rSWjd91x$ΜO[X!ɃR[Jp. -lIBO]305*^-bPx spW3Mkxޫ󞑈ym>^ZQA1=#t( 1z~1 ++ -HkN*"gR5'b$5=`{ %~jIHgF&y4r5CbHhS1AthT8!cGa.0?٧eXq7vۂ PǘGҸ!ƭ(X2 |{]#>rT7Dd6ڧu(a}.r (Ӯ;bPdQ SPe2[Nf*^6A(RCXܡ#֮#|~*STLV@^Y=e1_kqw2 ;);S}B"",@ -/&1Kg !1gOnAyP.^6|Qӑ i <7ڌ'AV>"f9#Z9o*t=aʚTRS'qvyлf"ټ}׵_Es>{4+&q@ )~;Z%Q׭e?Z}XT Aq#|~Ҿ]"tw46 tN@? 㘊q*!0K9"Ę:S\f]"ffpxw~M S/e5ܲY*t -!?0S(4Nz(u.R I۬Ҹ18<0p#zT H\Ot\Y":Ak<12 #| v}.734m*GU*k8Zl$cLQ[MJ/.A_x*z- 6ag/&mV|bݯ C<;y[T&Kg>ъ_l[dm_ =1Y]7<*@FKOEo)mjPK ?o%| .y;^\q*&+e/ { -Ld>U>VߵVdJ6\M_jA$V)G$B,S(颵zLVA;vcVh]!eu}{1AĐJܞ.⇾ÚeU<"ɥv46 .r2Je~,_5\MWIF+*auul\`}pb=-%$¥Rȇ JI_Wq&;ABNm3OrvZgXS2zsn'5aP MR EoWy(׭ l- -c7cc;0D=dnK{Vݵ?B8^$L9O=]ͲgW+E)Oå(W(7VCSM=8f)"8q E3l 𿉉klq3%:h&?T:(]/SJ4|P:\~f̂YFeC@_HÁ'uYk4V1<9bYk6 [X0ul}'M@AeWoB D4`[܆_yk< z2Ɩ ^4D˕ijN@wh 6*tX549? `^%wAcJp-ữ+qE˱ytȁD, Xp\Yّ$0RG46")N脹 xmUTY)iy - C(:{,H+o1VԖA/Zd^-?IO4"+0J*u>;?JƫuTbV$cC̯$ρ3qKR(VP\ڤj0;/Va#Cl=G8aaͬ\'Uca-ȇgPXtʜWY' -2*L6`Ƶa"l'z@.O2p~>]F#ni(JuGXN@heT V'$~!|t$,I3Pt|ʚ9$wB B=vAk/eQOS[_oվ ʋ{7M3Q֝9_zkf!Fg"P. [[Ry3IqBk[svduv<  -E(Lޯ9LC -& -S5f&w6 -&psfK8㋂CLdbz夞iJCY"#c:r)ul.Jl"9f#oQkVYNJVZqV:J lT*\:RW+sæ#b۾.#jkvS^8=_l7o8۝2AR$B }oFϩ0ed9PG{3/DŭF./[!69c:=pw+: KN=?C2x`ad?aCz^$fΘTS9鱪"g].åoaUplbb(④.cb'?,VqCX R%x'Yr'v0j7Ž(¦˯*Y3SG{#yv!c@ VE*#s/i`NBU"Os/~SێȻ,M%EY -؆;תnk`X*z2G7{gyXTb{I2dYMēi.blf ޤ1<+lop>y-LF.Q^th9>ėf S%!Ĺᠨ4p_fpiO!h2F_vvz>mNד۽a%a$[5Up*cLo {jɒ纉7eF(3HxbTY' KJNOW2¥g2{5\F-gfh+qy+8㜥wؖTa#ӿ.ܸ&OsAto -V?W/Pbk[(CJʭ|pT4OØg8 K[<!>RᦕКX$:-+-^2.p+[>?HO ;n'e!/v4٪̼K'fV@J3 cߜ)ƨEDnݒG&)omV?fUziԠkkRһǴٴ#+A̵]Zi@P~|G;#Ԉ$1]@iM=YМtuKv -W]Ұ2PS[ )BկDsRV*pm?J4S+!:WKǠEҜP&Z4eJS[ 3J! Ƹ@ԬXn \\j h*y }@5@5p+/)DjjUP] ܀uդO#}Bjvsܾ쳫 :q{va Xz.h7R~ -[jwei`3v\TV/~rDͣ {=eJk)3 sM)VȰ}WMfj!pa`'w)/oVŜefo9}sfGt&.`^=O C!|~лqhXx!r &q}x -D-ք"4ن̎U0= &K-P:.G5Q23qZ,l5C%Qr~k#d󽇐}zcJرT7k4]Uw:6mQMEНo_(1yJ[E⤎l,D'xhv5&'* ݦ? -c+2:\dfؗ; {_,G&!8wx)qvEvac" )涿Iۏوؚw-8!1]7dG #Ƃ6y4\<A3և4mjD)qr'>>թH=ѩS1Aw@%Iw0#y/7ݑAr>KJ|=ӾN/T'pߎyS9BJŲ8I"V *ߋ޳C zX?K 8KGAD0>$~fL10`KwC2x}ygkR/";T55*,!֛t)I _c=$F)iiz0`>P-j>sa sn~bJR]M9d3g<P#͡&% W.- f`}f~P G3cj@xҁB !׭L!رD挑VXl*:ek)ֱp#@Fn"*u DQXfDx)BIjVG8a_jt!61-p@=Nۣ)*G;@&ܠg$uti'@{7IDB} gM|Z4) _ T&"]74H*vYm[F=Xt^ټb@,;Az -!k ³=!"66X I _5]}/< -E"k!oIKWō`Vb ->K\Ű!_9ni& {5JGvs֢-w2ko}֕IH}05>΀PN hks #2d_$& ;lZ鬋3@rس7܊޴OZI bKlF&s61}. PZX0w$FUWH˯&TWڐu`i 0:냼-[sǚ%0ZRW\T"s8:5  !='-0'6h x4[%V;ɶnnʄz}ـ) ~6NMӋ#-)T}+ĜEy&*"+!dlDUI'c/.O@Ib$ \nw$'/W=nv׵a٨~&)?e9z&1c7l35PfKTU5Dr n|m69KʭW^% -S'2jW-25.z5ق@ʿ$7XT[eL[|P|mni;[TϪoIV_P%ȩi9Z[؅zn9g+oXOR 8!RYb!`VIk -(ap`bfo.nWwk{~ڜpLho/, K. e`A ;|aWա˃m^]pF ݻC!6P`e$B<)zW -[-Q U!*K-3Y?f8T s4w&6hF.h¯Î"䣻29Ig]Y:م+:8 2oO+zqU8j`a3OrS{ ;<ʏH+z*د;kW9ڏ ]wS&7L:U]&1SХѻoau5ysiZxufQ8nZ] ا[iZa+^/A8q(%4QBg(7B炈7~y=hn0"A.^Zկ6]Z;xO0n"3G4g'bࡌ@bMcPP\~V`\#pK > D*bXɩxw?)CfxCԟ 6[ؔ^gI|r%sZVlpςg2H 0@hNt;+K@'tYx PEW7xc봑WA]BFsڿ8yj~S9Դ"أsQWebVyFVt -k4_|UX2lzD ff"5|ğˢ!Iٻ&)Acqva 64a/,3!PX_KͿwPUaA~s慞/ Yrð5-RFg`ϴkc0/5,2?@G5dlu]tsZv3nq9臠fЯPY!*HP%p%3CtМnT%?*x|5(ȮEI@ ~Џ~t`|,(t ,8(0ts,![ -zc};Y-CVe)3 -}ʗPԞ~leBw_pc5N; 鱺Fʤ<(`g{ jr$07l p3ml?Ր=!׼?G+[i2j2c. n-~ȱ_w>ɽwWR3>@U@ͭOܼpQyzzFXb*fyJ#_DgI0p^ZcriL Ќ5ai9 o^+B8:Q߷Pnzp&BБD(0L\lZDPhb$erkz/ Zꧼ$žhaD FZGXI}a>k_RFdtU`0af llZ7\v-mW7|"pM楩)f !AĮT'u_ʰF?T\Yx9e?`LyΡ.]>ToTfd"jW%}K4t-)=\$AMiRNti fuh}|u$._@ -K6YӘ~@9~' A7YΠnW!dugoedtHs(LΡ"r-@]ŷ 7 %XE#=FWo8'O?35$fFNz4H:ė rխzr %!򓮏W<ʽ}Yf8S>V 9eJ8zT4ˀ(@u{>dײ|=:_A`z<JZ糅kzs6*)`TV` w(7O} Z#?|yX,; y6 "EfV2GU q#/Ħjo; >|AH#/sYtW*0F-"U1q$qk7mo0LۃM \fc/yO҇[ 1X(kve;Ƌd|Y - -DRMhj5DL\U>ͻ%!Z̚s? |ВWI]Kr$<̠0U܆fp|Cx.1ؤ/Ϧf>jH5bexnzv(9mR"=XѻN ̄[k!TW3"pkp)IiT_-NWN*l,읾n}3aN~or~ Wi׫ν8t/ /#iq9bu: $aZ%G,ͦBOF -do ̮%+~3UoEKT -jg#m k2+@O0dzg|s:0Я͌f1šI^E$ -=k-j'ɢwnhk%* Z?E)t9TZ ls[Z{ꕱjGʚ"+ 买!SFYR M4uqBKOJW5Y5ؔ4#comԣr{^U@:|$?@Nc|CrݞPDyrf__3&9[5z===KD@՞xuk%ʔ\,,=4{?E%t}^u<6G{9AX /7L>kNkx7@&]3V!G W|dΰEX&bT? 72-*\:HpDQOIBNhϣ&o"#mv> -6w4X"{r$(5pGQ3h,o!Fafg娵*"bRmf.w!tَU#c긿PȂ\* 90 @y')3Z{8|TV`@춂Q[]gwĀޞvѳĔKu[HX|W ģK˒e?.R&+3>DsJ=e`%-;qf P&3"6iD|CV98]najWs!=jfmu L&*Cq|ĜҹA_CgHYi//d}]Y+- Ek$T3_8 :P&C~[eޔ /G|6ts2Tu_*);E9=1[*sjqJir~WTS>96ї0q{ ~ZZatFk11BwK!Ery%4u-;1l7GdYeBNT-{~ﲕPVO浘](OV]U<63t0>Wn[l\l2GB1LnڥhmjS-ObV35ϧBG. -52 [i!SF\uGSdV:ߖjXwb<(qVbPwkLYӽ}0R-ZgqGC =0,1$`;&8Qٳ\VФeiP /¥Ѵ3zO[L΂\kOZ[WalkAv |t -#5c[tLU%wUHCBCŇj]tfipiu4ɩsK`jp{DD@3 ߟH!S6)$+#^ D;aHP~j]xDЛG;ϒy( ;cTjoÛ&qi7>蓨1<>BqkhLִ uʝ4މZgžiTEG׿@17>iAD*yda_\AH06y2w@X-Tv> vZY_I9%p)"LE* )NQo=!)4x[뮻GG=Uzk l|~ז>C` -Z6CO!KE˖W/ )#Z/d>~.^COSQkhdxm2.%77˚FyM9tnf;դ\X[ߠR<П8K#-qN7R},C$m>H{^/b7+-JaJ.1-q{h}| q|$yvqոY,]e#-nRD:C{Cda54nuUQ~R##}z]-Vu)I 375RDXK6TmAD8NO#Q+,<`Μg{pw;Ȑõ =W,D|\i7MparO&+QcT9V9X.1c^5JѢõf_ ).Ht7+Dkeyj]2l_Jw]@y!wPʧN>;D`8l>T@s~w# -RrC`Dq~RAf |VUz[kDY -%~7r+Wuq޾eovJ W: "F3pd5{DDy+a[@x ۵?q!a |K|SdTg@pT @M+$6DHb?WdžMVߘ˥GR:$)##](|A9P!k98%@dgSoZS{(_O=A\ -*s3 nw㛉ͻґt}+B5 -czabQa иD"#aj r%<_UMhN>/v8JSg)mQ -$ qe1QvfF9434x[Nߟ kvxJ+W8lqj HNBh`O - -l(AW WY>?mBZWJ,^SD@grRy99{Vբm瞴ۭ"xWA\,nwlkNtw"m F!ruy%%4>{0%guw IDo_kr7=NQ8ݯ# ("Z=~%U<͹[&E jmy:dACLo>ɹ\̞;ShSL` '>7` A-Su$je^ aXB;#ZPb0L=w"h/d~?74`1W";Aj9,3~OZSzH?EmꓚCݎ?U}_hDq;9W8Sj40t; {!I2K*_g=>"Ji"kR1Ó7>Aݜ㎡9Ր|̌ '&~-sR FkqŰ;dp@!<`t"gGB!>”5D`Vm[қ2sWQS@*}=Df3%wpYf'U~lzHK3_JfwahdW1R}n &z*p)4xLehdw}h%XmXƏRR̵wÃӠtO _M;J-G7Xa?e %ErV`h"4IՖ񿫒I)6\OU8H`:4dĐ:}#\\n%+n`!Aҿ$ވc2pSF›7f:KpWд̚v`L=C|t*4KC jE +ҞH#h`1D1 2DTP>bҪe=J{ 8 F yBIv̵O"OAi2󘰄{T|:g^1zY&|8N977>Y>sb]U>nhH ^ߏSl+"yq MLCaN@J:hG}]Hۓ'i - -=NVG@WqbGr;GBMf)MYNT(Aߖ3PT.ˎt=^kzb.ok\CoBCċN$jl$@["v)ɢ'Iy2œیG1m j"@1J7W@^E^C~QķoK ;03!KRx8SMM$O%P9V0V>&.ڄוjTWae ؛#V|dd#n Ep9R>Byq H,9l vnF|hcmY鸄⎔5a{:* !C8:wGAs(O] {ia 9Fd3eVp y(*?lw|F'J?k hwAH4*68,4U2\i}:ڇ0AuТWOkzˣbAҰ,5;fB"_he0u;DDqGR^\1hwEw1uc߯mqg >2~vg5o7Ǻ7i<]uX]vW-bcPL<$WrԼk, ѥ -oKl~m8G|)nd36MYy{x --m{ ͋@ucP'ϦzO)b/)Q0$[IYWANv%D!L'=Bq`ɀ/449|j%Y7TduvnÕNx{X_{W$V67XR;! $aUSގQGCydG ?y?档͹pfY+TfB| -y9F-90D7gSmphk.έu'̩fHxSʤ\ͅb/ltnzҍ^~|SU5D%1j8*'Ƒd3K8eµţ mwy+hh U$o^%4yx5qt׊ )R2-,-qTGBATai@ۀny#@F/>Vɍmtko St#n[󦒝]ڈ%gكB.o¢T1 V%춘,GP]S&+M3@[NsjZuT光Һ-c0MJ\OEQ_j / -  f2>ɣ2?ߜje7fcHढ.^ýTM pA54Z)ڍj8ID M@IhDgk2$˴_D{9QMmd F+<2#!Y.F?\";GAZjq"y>6/KWȇx5g)͜'rҧȂW"j,M{8QA -dWQ ;3CGbFH)Rmclg2Nm~~M||&Sb81'㣟Or|^}/W\2dт&6?/@p4/aKhUf~Pȗٟ b5i6 ƻZQ5D`'Х:#"+8|H>XH Ӊywgޅf%t#)5m&?wbM[hnZ!\~ZqW, d@89aE,ђwa_qc dWBuӟ[[/egԕbѮXE~ dQV@J].GtDk']'5O˟NtٰFDBN.f8GaY h~sM*l0!17?\fiwCn{$4~jrڴw#D[h2z -Tf p6]>66]@JޒTaR1l'ǹ̋$M1+,@y#jkNYܸS6 "4))MZ5>akD3!OɖbrŶtp~ ؀hPj| -Dn"(橴ɝrMȁcw\K''d1ш7ƶ"b?Qm^Xxz?)vw'd*%Øb9ɑ~kICj8u>jmC2}V?z&#JF ;;ھn /@^"*O.^cSLά,} Rkqů gUg՛&`nh?Q¸*{WXm/Bהe*b9,'$֗4\U ;Oe]`)_@3LҎh裡$ɼŁ 730c" jc}3CQA -Fʕ3%HMOLS/=|d#j{To,mŤ8@?M/F -\y ^ z07E$ J𬬕

΃ʚE -e2[epVny# X;Ayl$̣8&exFGZ9Mif ­ :S[:_ W\(,Y$됣4.f+N5 VnDld!~~n>[JPo_mCHOW` svyOҬY?.`,=Vm&PkVQAU]!*>=7Q':EJW?aVnтdhkVYB/vW^U S7"QVi 4[ęJ;=4@i^Ka^QJ0`--_ˡMCӰR<`&۷W]۩TETzU{MK) qI6 ,5,1F5> $b)3˓ZsNt}K$Vl~3Mz⯥=s.Td'&Rd_+/9{8(z~B؈\ot f??ʔHv.)+2#ckgФ&) >,c)y|cL3oScesk.FɍmOyo[z`!0vb$Nϴ7ߨ͡7A^(RM:V:.sQKD?BXhJhK,hY29rn_-dX@k(랓 kԏ;tT+94LS]a TE@, ʫVt/]KImtF{kU[3M4f篧rGܭkOט=?m|DXL -[H_f7` o6xrWMh/S.:Tkf`kꠥo^cq* 7p8K@ ]$)|m^ ^:C@XCFK"m$/S>د Bك$ Lbdz~ ٲa9_BdPImXaWqsn1#vX)Ac4:bb5iJSwViGy|]Z% 2Q1J&Lԓtg I0OQ!w#UbTOjEG&|;C%lQPvFD~QRda´ -WThpnߺcNCz?;?F]*&G+j0$ReGI vw]=085#/Fpdsjj-Oï_VZ>ŖݨuT-ܖ59SaDgAw<7F%^()ZĔEQ]W_UfҋzJ;ʐz@&[Tum9gfj= M0F=8#]kiZp%6%g~A^IM aBw*"ּ̈́6*⥈P{ ;Toa|We+B!{9;@ -MH('pA<2MɧQ4(iWnAwV5!&߄;F<:u`m\ۭ*)n#՜=%2;q?JBY+mx oet}Xl9-{#ToXhW=y *l@?-C4L&?U/^8hApJ'yS\enAw݊_uL3j11ng]GPWVt]iS`{^B'u81m @i`)[87HR<@hgUk\tNg}W`iҘrO{(ϳ8ŖBΨi&/8d -vaW6a9?(ٵC?e`]Yknp'~mX`4c̲?7rYF_5QS;{d?}v'ų[ S:nsi.ix|Gj]kh(H=Ϯ -zY&HP* hnkP }iH,V"F^Vwݞ<dO%^dn7C|GkLd/t9+QGrԇ-oiTw;;j}0#(0IF_7X_h s&̮݈¦z#w%IZLGS(y -Kݔ Bas;+2J ?R9xONK]njn%e-/ - =ҥa#}쵼`mִâodMKؘP>1˛+jO\}]v`xsۛa[\q>dSA%+mɸrnuEizU@tv"pP׸c쩗|(|nlYH$9 y>8YgU;qeKPBeVt JRP#&5rP`~ -a"Kwm%|\;8q.Ejh~  iIPD$PΩl]SYZNx㦉 I Jen:B?V6PgV8or5uDH -|Ɏe')F~cpRpx hG P",n:e.X-|KйmrjY{H566+G-58oCԴ/BVE<3& YIP6:8;V{~)SD5vw|fj۾-I:qDd(ASXjM!\wMMUݾ[U~ﳐqۚ.|t$#ǕQ -z~w6.Q(EWj:kJաjXa&Į6>'0jت8G lhNvuoF5dC="xQ(+VE)c\,+} &S~87(*)[v $A/5y-ݭ5pB-)Ad5]$=t`!U9pjbF.0E禓`zզdX¦uiU2qv @r%lGFD2N ?[T/}}Lm+Y*-v2 ( a1mXal~Z[BEg>x66CܕHvJԴZc=?;A9ȨX]CA^<[=D獘 /!a !d,a*DgBYwXoYR"[z!ĥVl=BV)Lg2?]QV8+&] \ ^>]UJʏ`Tu Jr1xi] c"2h}kGIHd_p0ƽiji"0QD]seR"wcigV`"V(LuӜߊPFT<%5iȺEе}RSE E|j+~NoikIY{ QcɈ>>OPbkF I<JH0KMvv\-zjo9/c9\H]+ϞP&K[1gO: >m#(n~aȇAv;3@z g5osHX~D TG: iYt~ Ur^8zo /朜od*=V}IYd@*ߏBQEYlO\۟s^;wuȑ *+:^]F ;w.ޝR@AO=2=+%vAYd=Vhwύunӧ^ȭ=-;h &#C Xx3-[z.2$kV\^(~Xv Mb|'Ǝ׫Ú׳)P5If 8I#+34l-hB4 d:>ԔuIFlDe|Tqg*j7F~6vէ_,P D b0_kb񙦳JU4Ԥ:7|3rN`HprR\+oq4+ҷDĺ[&*/2κI2Z# >VvFѐY?JhDgèpRkж3 \X>'ä>dFZ8O7~)%zݵ(yU_MXia]WcPeųqAP*MǺѤ fFw-4ă:0^y" m>n+z1]Pn+syuםG2 -/s]P#4?bX5aޯQOKF"ocӊuO; H[%P̯D4q'Лr)☬"ê7Z`q9i?SnkQhh1s3|v}S؏WӱPaWJYaÎ}霮f[YGp*MXqjLs5Ma뿁lb꛰bY5!ǦDt0EJOyO-͋`3@"hX.Oɒ-oq^٦?Ozuh]/}Ax/~:u+5rQS2Ң|c-qn3PȂlHLLBa2_fۄws,%44 9op)/C bGoռ} -c3PoKH~^tt&c%fCv6*^* -F5TN;Yq7O{7[&-yi0)5Ռ<]T)b^$(vŸ Blv[: -]n*Vk'$0I5(҃|y#IЩi ی(j*7_35| `Ezҭ[dx5v1n<4B:428fX `87A5q,Y#>)=`YdcJ顄wrqr ˮö3H -]r4 -I,^A4/./sVIDCDƈk^YXY۝snmn𲕈Ǫܿ/DYn0E(Z=0+*+oRE@?@„gZUTUי|ojij쮑~æػ+þ@Uj,A$V9,'&'kNA<;