From 6a9b082f97e367325c7c2aed5a701ea60c45bd01 Mon Sep 17 00:00:00 2001 From: Evan Reichard Date: Mon, 3 Aug 2026 21:08:35 -0400 Subject: [PATCH] feat(runtime): embed platform modules as bytecode ui.lua and hints.lua are compiled to LUA_32BITS bytecode (matching the firmware's Lua build) and linked into the binary. A new package.searchers entry checks them as the fallback after the SD card, so a local /.lua/lib/ui.lua still shadows the packaged one for debugging. Bytecode is ~40% smaller than source and loads without parsing. A fresh SD card with no make sdcard now has the platform available. --- - | Bin 0 -> 7606 bytes Makefile | 13 +- lua/lib/hints.lua | 50 +-- lua/lib/ui.lua | 464 +++++++++++++------------- native/include/lua/embedded_modules.h | 18 + native/include/lua/runtime.h | 1 + native/src/embedded_modules.cpp | 15 + native/src/runtime/loader.cpp | 29 +- tools/dump.c | 36 ++ tools/embed.py | 67 ++++ 10 files changed, 430 insertions(+), 263 deletions(-) create mode 100644 - create mode 100644 native/include/lua/embedded_modules.h create mode 100644 native/src/embedded_modules.cpp create mode 100644 tools/dump.c create mode 100644 tools/embed.py diff --git a/- b/- new file mode 100644 index 0000000000000000000000000000000000000000..ea2e3c9641330fcbc3569c3a72c3bd1889dd8a8d GIT binary patch literal 7606 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 literal 0 HcmV?d00001 diff --git a/Makefile b/Makefile index ea418a4..419a5d3 100644 --- a/Makefile +++ b/Makefile @@ -10,10 +10,14 @@ LUA_OBJECTS := $(patsubst native/src/vendor/lua/%.c,_build/lua/%.o,$(LUA_C)) LUA_LIBRARY := _build/liblua.a LUA_SMOKE := _build/lua-smoke RUNTIME_TEST := _build/runtime-test +LUAC32 := _build/luac32 RUNTIME_CPP := $(sort $(wildcard native/src/runtime/*.cpp native/src/bindings/core/*.cpp \ - native/src/bindings/features/*.cpp)) + native/src/bindings/features/*.cpp) native/src/embedded_modules.cpp) -.PHONY: api test +.PHONY: api test embed + +embed: $(LUAC32) + @$(PYTHON) tools/embed.py $(LUAC32) lua/lib native/src/embedded_modules.cpp api: @$(PYTHON) tools/gen_api.py @@ -21,6 +25,8 @@ api: test: $(LUA_SMOKE) $(RUNTIME_TEST) @$(PYTHON) tools/gen_api.py --check @printf '%-32s ' generated-api; echo ok + @$(PYTHON) tools/embed.py $(LUAC32) lua/lib native/src/embedded_modules.cpp --check + @printf '%-32s ' embedded-modules; echo ok @$(LUA) -e 'assert(_VERSION == "Lua 5.4", "tests require Lua 5.4")' @for file in $(CONTRACTS); do $(LUA) -e "assert(loadfile('$$file'))" || exit 1; done @printf '%-32s ' contracts; echo ok @@ -39,6 +45,9 @@ $(RUNTIME_TEST): $(RUNTIME_CPP) native/test/runtime_test.cpp $(LUA_LIBRARY) $(LUA_LIBRARY): $(LUA_OBJECTS) @$(AR) rcs $@ $^ +$(LUAC32): tools/dump.c $(LUA_LIBRARY) + @$(CC) -std=c99 -DLUA_32BITS -I native/src/vendor/lua $< $(LUA_LIBRARY) -lm -o $@ + _build/lua/%.o: native/src/vendor/lua/%.c @mkdir -p $(@D) @$(CC) -std=c99 -DLUA_32BITS -I native/src/vendor/lua -c $< -o $@ diff --git a/lua/lib/hints.lua b/lua/lib/hints.lua index 59d9083..e8fc1f5 100644 --- a/lua/lib/hints.lua +++ b/lua/lib/hints.lua @@ -4,42 +4,42 @@ local hints = {} -- Reading order across the strip, so a device showing three of them still reads left to right. -local ORDER = {"back", "left", "up", "down", "right", "confirm"} +local ORDER = { "back", "left", "up", "down", "right", "confirm" } local function available() - local roles = {} - if input and input.getButtons then - for _, role in ipairs(input.getButtons()) do roles[role] = true end - end - return roles + local roles = {} + if input and input.getButtons then + for _, role in ipairs(input.getButtons()) do roles[role] = true end + end + return roles end ---Paints the labels this device can actually act on, and returns the height it used. ---@param actions table Label per Button role; roles the device lacks are skipped. ---@param options table|nil `y`, `font`, `color`, and `background` overrides. function hints.draw(actions, options) - options = options or {} - local font = options.font or gui.FONT_SMALL - local color = options.color or gui.color(0, 0, 0) - local background = options.background or gui.color(255, 255, 255) - local height = gui.getFontHeight(font) + 6 - local y = options.y or (gui.getHeight() - height) + options = options or {} + local font = options.font or gui.FONT_SMALL + local color = options.color or gui.color(0, 0, 0) + local background = options.background or gui.color(255, 255, 255) + local height = gui.getFontHeight(font) + 6 + local y = options.y or (gui.getHeight() - height) - local roles = available() - local labels = {} - for _, role in ipairs(ORDER) do - if roles[role] and actions[role] then labels[#labels + 1] = actions[role] end - end + local roles = available() + local labels = {} + for _, role in ipairs(ORDER) do + if roles[role] and actions[role] then labels[#labels + 1] = actions[role] end + end - gui.fillRect(0, y, gui.getWidth(), height, background) - if #labels == 0 then return height end + gui.fillRect(0, y, gui.getWidth(), height, background) + if #labels == 0 then return height end - local slot = gui.getWidth() // #labels - for index, label in ipairs(labels) do - local left = slot * (index - 1) + (slot - gui.getTextWidth(font, label)) // 2 - gui.drawText(font, left, y + 3, label, color, gui.STYLE_NORMAL, background) - end - return height + local slot = gui.getWidth() // #labels + for index, label in ipairs(labels) do + local left = slot * (index - 1) + (slot - gui.getTextWidth(font, label)) // 2 + gui.drawText(font, left, y + 3, label, color, gui.STYLE_NORMAL, background) + end + return height end return hints diff --git a/lua/lib/ui.lua b/lua/lib/ui.lua index 086256a..afc4e72 100644 --- a/lua/lib/ui.lua +++ b/lua/lib/ui.lua @@ -44,9 +44,9 @@ local ui = {} local THEME_PATH = "/.lua/theme" local THEMES = { - light = {background = {255, 255, 255}, color = {0, 0, 0}, accent = {0, 120, 255}, radius = 6}, - dark = {background = {18, 18, 20}, color = {235, 235, 235}, accent = {166, 118, 255}, radius = 6}, - mono = {background = {255, 255, 255}, color = {0, 0, 0}, accent = {0, 0, 0}, radius = 0}, + light = { background = { 255, 255, 255 }, color = { 0, 0, 0 }, accent = { 0, 120, 255 }, radius = 6 }, + dark = { background = { 18, 18, 20 }, color = { 235, 235, 235 }, accent = { 166, 118, 255 }, radius = 6 }, + mono = { background = { 255, 255, 255 }, color = { 0, 0, 0 }, accent = { 0, 0, 0 }, radius = 0 }, } local enterHandlers, exitHandlers, clickHandlers, painters = {}, {}, {}, {} @@ -59,123 +59,123 @@ local activeScreen local applyPalette local function mix(a, b, amount) - local out = {} - for i = 1, 3 do out[i] = math.floor(a[i] + (b[i] - a[i]) * amount + 0.5) end - return out + local out = {} + for i = 1, 3 do out[i] = math.floor(a[i] + (b[i] - a[i]) * amount + 0.5) end + return out end local function color(rgb) - return gui.color(rgb[1], rgb[2], rgb[3]) + return gui.color(rgb[1], rgb[2], rgb[3]) end local function palette(seed) - local background, foreground, accent = seed.background, seed.color, seed.accent - return { - background = color(background), - color = color(foreground), - muted = color(mix(foreground, background, 0.45)), - accent = color(accent), - face = color(mix(background, foreground, 0.08)), - pressedFace = color(accent), - pressedColor = color(background), - focusColor = color(accent), - radius = seed.radius, - } + local background, foreground, accent = seed.background, seed.color, seed.accent + return { + background = color(background), + color = color(foreground), + muted = color(mix(foreground, background, 0.45)), + accent = color(accent), + face = color(mix(background, foreground, 0.08)), + pressedFace = color(accent), + pressedColor = color(background), + focusColor = color(accent), + radius = seed.radius, + } end local function loadTheme(name) - themeName = THEMES[name] and name or "light" - ui.theme = palette(THEMES[themeName]) + themeName = THEMES[name] and name or "light" + ui.theme = palette(THEMES[themeName]) end ---@return string function ui.getTheme() - return themeName + return themeName end ---@return string[] function ui.themeNames() - local names = {} - for name in pairs(THEMES) do names[#names + 1] = name end - table.sort(names) - return names + local names = {} + for name in pairs(THEMES) do names[#names + 1] = name end + table.sort(names) + return names end ---@param name string ---@return true? ok ---@return string? error function ui.setTheme(name) - if not THEMES[name] then return nil, "Unknown theme" end - local ok, err = fs.writeFile(THEME_PATH, name) - if not ok then return nil, err end - loadTheme(name) - if activeScreen then - applyPalette(activeScreen.root) - gui.clear(ui.theme.background) - node.invalidate(activeScreen.root) - end - return true + if not THEMES[name] then return nil, "Unknown theme" end + local ok, err = fs.writeFile(THEME_PATH, name) + if not ok then return nil, err end + loadTheme(name) + if activeScreen then + applyPalette(activeScreen.root) + gui.clear(ui.theme.background) + node.invalidate(activeScreen.root) + end + return true end local savedTheme = fs.readFile(THEME_PATH, 32) loadTheme(savedTheme and savedTheme:match("^%s*(.-)%s*$") or "light") local function clearState() - enterHandlers, exitHandlers, clickHandlers, painters = {}, {}, {}, {} - pressStyles = {} + enterHandlers, exitHandlers, clickHandlers, painters = {}, {}, {}, {} + pressStyles = {} end node.setPainter(function(id, x, y, w, h) - local painter = painters[id] - if painter then painter(id, x, y, w, h) end + local painter = painters[id] + if painter then painter(id, x, y, w, h) end end) local STYLE_KEYS = { - "color", "fill", "border", "face", "pressedFace", "pressedColor", - "focusColor", "radius", "font", "textStyle", + "color", "fill", "border", "face", "pressedFace", "pressedColor", + "focusColor", "radius", "font", "textStyle", } local function applyStyle(id, spec) - local style, hasStyle = {}, false - for _, key in ipairs(STYLE_KEYS) do - if spec[key] ~= nil then - style[key], hasStyle = spec[key], true - end - end - if spec.background ~= nil then - style.background, style.fill, hasStyle = spec.background, spec.background, true - end - if hasStyle then node.setStyle(id, style) end + local style, hasStyle = {}, false + for _, key in ipairs(STYLE_KEYS) do + if spec[key] ~= nil then + style[key], hasStyle = spec[key], true + end + end + if spec.background ~= nil then + style.background, style.fill, hasStyle = spec.background, spec.background, true + end + if hasStyle then node.setStyle(id, style) end end local function build(spec, kind) - spec = spec or {} - if laidOut then ui.reset() end + spec = spec or {} + if laidOut then ui.reset() end - local children = {} - for index, child in ipairs(spec) do - children[index] = child - spec[index] = nil - end + local children = {} + for index, child in ipairs(spec) do + children[index] = child + spec[index] = nil + end - spec.type = kind - spec.interactive = spec.on_enter ~= nil or spec.on_exit ~= nil or spec.on_click ~= nil - local id = node.create(nil, spec) - for _, child in ipairs(children) do node.attach(id, child) end + spec.type = kind + spec.interactive = spec.on_enter ~= nil or spec.on_exit ~= nil or spec.on_click ~= nil + local id = node.create(nil, spec) + for _, child in ipairs(children) do node.attach(id, child) end - applyStyle(id, spec) - enterHandlers[id] = spec.on_enter - exitHandlers[id] = spec.on_exit - clickHandlers[id] = spec.on_click - painters[id] = spec.paint - pressStyles[id] = spec.press_style ~= false - return id + applyStyle(id, spec) + enterHandlers[id] = spec.on_enter + exitHandlers[id] = spec.on_exit + clickHandlers[id] = spec.on_click + painters[id] = spec.paint + pressStyles[id] = spec.press_style ~= false + return id end ---@param spec UiSpec ---@return NodeId function ui.box(spec) - return build(spec, "box") + return build(spec, "box") end ---Side length for a grid of square cards that fits the frame, and the column count that @@ -187,112 +187,112 @@ end ---@return integer side ---@return integer columns function ui.cardSide(count, pad, gap, reserve) - local columns = gui.getWidth() >= gui.getHeight() and 4 or 3 - local rows = math.ceil(count / columns) - local byWidth = (gui.getWidth() - 2 * pad - (columns - 1) * gap) // columns - local byHeight = (gui.getHeight() - 2 * pad - (reserve or 0) - (rows - 1) * gap) // rows - return math.min(byWidth, byHeight), columns + local columns = gui.getWidth() >= gui.getHeight() and 4 or 3 + local rows = math.ceil(count / columns) + local byWidth = (gui.getWidth() - 2 * pad - (columns - 1) * gap) // columns + local byHeight = (gui.getHeight() - 2 * pad - (reserve or 0) - (rows - 1) * gap) // rows + return math.min(byWidth, byHeight), columns end ---@param spec UiSpec ---@return NodeId function ui.spacer(spec) - spec = spec or {} - return build({w = spec.w, h = spec.h}, "box") + spec = spec or {} + return build({ w = spec.w, h = spec.h }, "box") end ---@param text string ---@param spec? UiSpec ---@return NodeId function ui.text(text, spec) - spec = spec or {} - spec.label = text - spec.textStyle, spec.style = spec.style, nil - return build(spec, "text") + spec = spec or {} + spec.label = text + spec.textStyle, spec.style = spec.style, nil + return build(spec, "text") end ---@param text string ---@param spec? UiSpec ---@return NodeId function ui.label(text, spec) - spec = spec or {} - local font, style = spec.font or gui.FONT_UI, spec.style or gui.STYLE_NORMAL - if spec.fit and gui.getTextWidth(font, text, style) > spec.fit then - while #text > 1 and gui.getTextWidth(font, text .. "~", style) > spec.fit do - text = text:sub(1, -2) - end - text = text .. "~" - end - spec.w = gui.getTextWidth(font, text, style) - spec.h = gui.getFontHeight(font, style) - spec.font, spec.fit = font, nil - return ui.text(text, spec) + spec = spec or {} + local font, style = spec.font or gui.FONT_UI, spec.style or gui.STYLE_NORMAL + if spec.fit and gui.getTextWidth(font, text, style) > spec.fit then + while #text > 1 and gui.getTextWidth(font, text .. "~", style) > spec.fit do + text = text:sub(1, -2) + end + text = text .. "~" + end + spec.w = gui.getTextWidth(font, text, style) + spec.h = gui.getFontHeight(font, style) + spec.font, spec.fit = font, nil + return ui.text(text, spec) end ---@param spec UiSpec ---@return NodeId function ui.button(spec) - spec = spec or {} - spec.pad = spec.pad or 8 - spec.align = spec.align or "center" - local label, font = spec.label, spec.font - spec.label = nil - local id = build(spec, "button") - if label then node.create(id, {type = "text", label = label, font = font or gui.FONT_UI}) end - return id + spec = spec or {} + spec.pad = spec.pad or 8 + spec.align = spec.align or "center" + local label, font = spec.label, spec.font + spec.label = nil + local id = build(spec, "button") + if label then node.create(id, { type = "text", label = label, font = font or gui.FONT_UI }) end + return id end ---@param spec UiSpec ---@return NodeId function ui.custom(spec) - return build(spec, "custom") + return build(spec, "custom") end ---@param id NodeId ---@param text string function ui.setText(id, text) - if node.getLabel(id) == text then return end - node.setLabel(id, text) - node.invalidate(id) + if node.getLabel(id) == text then return end + node.setLabel(id, text) + node.invalidate(id) end ---@param id NodeId function ui.invalidate(id) - node.invalidate(id) + node.invalidate(id) end ---@param spec UiConfirmSpec ---@return NodeId function ui.confirm(spec) - local card = { - w = spec.w or 0.85, - pad = 16, - gap = 12, - background = spec.background or ui.theme.background, - border = spec.border or ui.theme.muted, - ui.text(spec.title), - } - if spec.message then card[#card + 1] = ui.text(spec.message, {color = ui.theme.muted}) end + local card = { + w = spec.w or 0.85, + pad = 16, + gap = 12, + background = spec.background or ui.theme.background, + border = spec.border or ui.theme.muted, + ui.text(spec.title), + } + if spec.message then card[#card + 1] = ui.text(spec.message, { color = ui.theme.muted }) end - local buttons = {row = true, gap = 8, justify = "end"} - if spec.cancel ~= false then - buttons[#buttons + 1] = ui.button{label = spec.cancel or "cancel", on_click = spec.on_cancel} - end - buttons[#buttons + 1] = ui.button{label = spec.ok or "ok", on_click = spec.on_ok} - card[#card + 1] = ui.box(buttons) + local buttons = { row = true, gap = 8, justify = "end" } + if spec.cancel ~= false then + buttons[#buttons + 1] = ui.button { label = spec.cancel or "cancel", on_click = spec.on_cancel } + end + buttons[#buttons + 1] = ui.button { label = spec.ok or "ok", on_click = spec.on_ok } + card[#card + 1] = ui.box(buttons) - return ui.box{ - at = {x = 0, y = 0}, w = "fill", h = "fill", capture = true, - align = "center", justify = "center", on_click = spec.on_outside, - ui.box(card), - } + return ui.box { + at = { x = 0, y = 0 }, w = "fill", h = "fill", capture = true, + align = "center", justify = "center", on_click = spec.on_outside, + ui.box(card), + } end function ui.reset() - node.reset() - clearState() - laidOut = false - activeScreen = nil + node.reset() + clearState() + laidOut = false + activeScreen = nil end ---@class UiScreen @@ -300,159 +300,159 @@ local Screen = {} Screen.__index = Screen applyPalette = function(root) - -- The root is the panel background, not a card: no border, so it takes the fast fillRect - -- path rather than the per-pixel roundRect one. Radius stays so cards inherit it. - node.setStyle(root, { - color = ui.theme.color, - background = ui.theme.background, - face = ui.theme.face, - pressedFace = ui.theme.pressedFace, - pressedColor = ui.theme.pressedColor, - focusColor = ui.theme.focusColor, - radius = ui.theme.radius, - font = gui.FONT_UI, - }) + -- The root is the panel background, not a card: no border, so it takes the fast fillRect + -- path rather than the per-pixel roundRect one. Radius stays so cards inherit it. + node.setStyle(root, { + color = ui.theme.color, + background = ui.theme.background, + face = ui.theme.face, + pressedFace = ui.theme.pressedFace, + pressedColor = ui.theme.pressedColor, + focusColor = ui.theme.focusColor, + radius = ui.theme.radius, + font = gui.FONT_UI, + }) end ---@param root NodeId ---@param style? NodeStyle ---@return UiScreen function ui.screen(root, style) - node.setSize(root, "fill", "fill") - applyPalette(root) - if style then node.setStyle(root, style) end - local screen = setmetatable({root = root}, Screen) - activeScreen = screen - screen:relayout() - return screen + node.setSize(root, "fill", "fill") + applyPalette(root) + if style then node.setStyle(root, style) end + local screen = setmetatable({ root = root }, Screen) + activeScreen = screen + screen:relayout() + return screen end function Screen:relayout() - local ok, err = node.layout(self.root, 0, 0, gui.getWidth(), gui.getHeight()) - if not ok then error(err, 2) end - node.dropScratch() - laidOut = true - gui.clear(ui.theme.background) + local ok, err = node.layout(self.root, 0, 0, gui.getWidth(), gui.getHeight()) + if not ok then error(err, 2) end + node.dropScratch() + laidOut = true + gui.clear(ui.theme.background) end function Screen:draw() - node.draw(self.root) + node.draw(self.root) end local function inside(id, x, y) - local rx, ry, rw, rh = node.getRect(id) - return x >= rx and x < rx + rw and y >= ry and y < ry + rh + local rx, ry, rw, rh = node.getRect(id) + return x >= rx and x < rx + rw and y >= ry and y < ry + rh end local function enter(id, x, y) - if pressStyles[id] then node.setPressed(id, true) end - local handler = enterHandlers[id] - if handler then handler(id, x, y) end + if pressStyles[id] then node.setPressed(id, true) end + local handler = enterHandlers[id] + if handler then handler(id, x, y) end end local function exit(id, x, y) - if pressStyles[id] then node.setPressed(id, false) end - local handler = exitHandlers[id] - if handler then handler(id, x, y) end + if pressStyles[id] then node.setPressed(id, false) end + local handler = exitHandlers[id] + if handler then handler(id, x, y) end end ---@param x integer ---@param y integer ---@return boolean handled function Screen:down(x, y) - local focused = node.getFocus() - if focused then - node.setFocus(nil) - local handler = exitHandlers[focused] - if handler then handler(focused) end - end + local focused = node.getFocus() + if focused then + node.setFocus(nil) + local handler = exitHandlers[focused] + if handler then handler(focused) end + end - local target = node.hit(self.root, x, y) - if not target then return false end - self.captured, self.inside = target, true - enter(target, x, y) - return true + local target = node.hit(self.root, x, y) + if not target then return false end + self.captured, self.inside = target, true + enter(target, x, y) + return true end ---@param x integer ---@param y integer ---@return boolean handled function Screen:move(x, y) - local target = self.captured - if not target then return false end - local isInside = inside(target, x, y) - if isInside ~= self.inside then - self.inside = isInside - if isInside then enter(target, x, y) else exit(target, x, y) end - end - return true + local target = self.captured + if not target then return false end + local isInside = inside(target, x, y) + if isInside ~= self.inside then + self.inside = isInside + if isInside then enter(target, x, y) else exit(target, x, y) end + end + return true end ---@param x integer ---@param y integer ---@return boolean handled function Screen:up(x, y) - local target = self.captured - if not target then return false end - local wasActive = self.inside - local releasedInside = inside(target, x, y) - local handler = releasedInside and clickHandlers[target] or nil - self.captured, self.inside = nil, nil - if wasActive then exit(target, x, y) end - if handler then handler(target, x, y) end - return true + local target = self.captured + if not target then return false end + local wasActive = self.inside + local releasedInside = inside(target, x, y) + local handler = releasedInside and clickHandlers[target] or nil + self.captured, self.inside = nil, nil + if wasActive then exit(target, x, y) end + if handler then handler(target, x, y) end + return true end -local DIRECTIONS = {up = true, down = true, left = true, right = true} +local DIRECTIONS = { up = true, down = true, left = true, right = true } local function focusFirst(screen) - local focused = node.focusFirst(screen.root) - if focused then - local handler = enterHandlers[focused] - if handler then handler(focused) end - end - return focused + local focused = node.focusFirst(screen.root) + if focused then + local handler = enterHandlers[focused] + if handler then handler(focused) end + end + return focused end ---@param name string Button name; directions and confirm are handled. ---@param pressed boolean ---@return boolean handled function Screen:button(name, pressed) - if type(pressed) ~= "boolean" then error("button state must be boolean", 2) end + if type(pressed) ~= "boolean" then error("button state must be boolean", 2) end - if DIRECTIONS[name] then - if not pressed then return true end - local previous = node.getFocus() - if not previous then - focusFirst(self) - return true - end - local focused = node.moveFocus(self.root, name) - if focused ~= previous then - local leave = exitHandlers[previous] - if leave then leave(previous) end - local arrive = enterHandlers[focused] - if arrive then arrive(focused) end - end - return true - end + if DIRECTIONS[name] then + if not pressed then return true end + local previous = node.getFocus() + if not previous then + focusFirst(self) + return true + end + local focused = node.moveFocus(self.root, name) + if focused ~= previous then + local leave = exitHandlers[previous] + if leave then leave(previous) end + local arrive = enterHandlers[focused] + if arrive then arrive(focused) end + end + return true + end - if name ~= "confirm" then return false end - local focused = node.getFocus() or focusFirst(self) - if not focused then return false end - if pressed then - node.setPressed(focused, true) - self.confirming = focused - else - local target = self.confirming - self.confirming = nil - if target then - node.setPressed(target, false) - local handler = clickHandlers[target] - if handler then handler(target) end - end - end - return true + if name ~= "confirm" then return false end + local focused = node.getFocus() or focusFirst(self) + if not focused then return false end + if pressed then + node.setPressed(focused, true) + self.confirming = focused + else + local target = self.confirming + self.confirming = nil + if target then + node.setPressed(target, false) + local handler = clickHandlers[target] + if handler then handler(target) end + end + end + return true end return ui diff --git a/native/include/lua/embedded_modules.h b/native/include/lua/embedded_modules.h new file mode 100644 index 0000000..6d2e07b --- /dev/null +++ b/native/include/lua/embedded_modules.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace esp32lua { + +// A platform module compiled to bytecode and linked into the firmware. The module searcher +// tries the SD card first, so a local copy shadows the packaged one. +struct EmbeddedModule { + const char* name; + const unsigned char* data; + size_t size; +}; + +extern const EmbeddedModule embedded_modules[]; +extern const size_t embedded_modules_count; + +} // namespace esp32lua diff --git a/native/include/lua/runtime.h b/native/include/lua/runtime.h index b914495..279dd33 100644 --- a/native/include/lua/runtime.h +++ b/native/include/lua/runtime.h @@ -128,6 +128,7 @@ class Runtime { bool loadScript(const std::string& path); void installLoader(const std::string& appDir); static int searchModule(lua_State* state); + static int searchEmbedded(lua_State* state); static int loadFile(lua_State* state); // A batch is one visit to the app, however many callbacks it fans out into: a tap fires diff --git a/native/src/embedded_modules.cpp b/native/src/embedded_modules.cpp new file mode 100644 index 0000000..b60368a --- /dev/null +++ b/native/src/embedded_modules.cpp @@ -0,0 +1,15 @@ +// GENERATED by tools/embed.py — do not edit. Run `make embed` to regenerate. +#include + +namespace esp32lua { + +static const unsigned char hints[] = {0x1b, 0x4c, 0x75, 0x61, 0x54, 0x00, 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a, 0x04, 0x04, 0x04, 0x78, 0x56, 0x00, 0x00, 0x00, 0x40, 0xb9, 0x43, 0x01, 0x80, 0x80, 0x80, 0x00, 0x01, 0x08, 0x91, 0x51, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x06, 0x52, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x83, 0x81, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x83, 0x82, 0x01, 0x00, 0x03, 0x03, 0x02, 0x00, 0x83, 0x83, 0x02, 0x00, 0xce, 0x00, 0x06, 0x00, 0x4f, 0x01, 0x00, 0x00, 0xcf, 0x81, 0x00, 0x00, 0x12, 0x00, 0x06, 0x03, 0x46, 0x80, 0x02, 0x01, 0xc6, 0x81, 0x01, 0x01, 0x87, 0x04, 0x85, 0x62, 0x61, 0x63, 0x6b, 0x04, 0x85, 0x6c, 0x65, 0x66, 0x74, 0x04, 0x83, 0x75, 0x70, 0x04, 0x85, 0x64, 0x6f, 0x77, 0x6e, 0x04, 0x86, 0x72, 0x69, 0x67, 0x68, 0x74, 0x04, 0x88, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x04, 0x85, 0x64, 0x72, 0x61, 0x77, 0x81, 0x01, 0x00, 0x00, 0x82, 0x80, 0x89, 0x8f, 0x00, 0x00, 0x08, 0x95, 0x13, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xb8, 0x06, 0x00, 0x80, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x01, 0xc2, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x80, 0x8b, 0x00, 0x00, 0x02, 0x0b, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x02, 0x01, 0x44, 0x01, 0x01, 0x00, 0xc4, 0x00, 0x00, 0x05, 0xcb, 0x80, 0x00, 0x00, 0x10, 0x80, 0x06, 0x03, 0xcc, 0x00, 0x00, 0x02, 0xcd, 0x80, 0x01, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x46, 0x80, 0x02, 0x00, 0xc6, 0x80, 0x01, 0x00, 0x84, 0x04, 0x86, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x04, 0x8b, 0x67, 0x65, 0x74, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x73, 0x04, 0x87, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, 0x11, 0x81, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x94, 0xab, 0x02, 0x00, 0x19, 0xf8, 0xc2, 0x80, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x13, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x02, 0x00, 0x0e, 0x01, 0x01, 0x00, 0x42, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x0b, 0x01, 0x00, 0x01, 0x0e, 0x01, 0x02, 0x02, 0x8e, 0x01, 0x01, 0x03, 0xc2, 0x81, 0x00, 0x00, 0xb8, 0x02, 0x00, 0x80, 0x8b, 0x01, 0x00, 0x01, 0x8e, 0x01, 0x03, 0x03, 0x01, 0x82, 0xff, 0x7f, 0x81, 0x82, 0xff, 0x7f, 0x01, 0x83, 0xff, 0x7f, 0xc4, 0x01, 0x04, 0x02, 0x0e, 0x02, 0x01, 0x04, 0x42, 0x82, 0x00, 0x00, 0xb8, 0x02, 0x00, 0x80, 0x0b, 0x02, 0x00, 0x01, 0x0e, 0x02, 0x04, 0x03, 0x81, 0x02, 0x7f, 0x80, 0x01, 0x03, 0x7f, 0x80, 0x81, 0x03, 0x7f, 0x80, 0x44, 0x02, 0x04, 0x02, 0x8b, 0x02, 0x00, 0x01, 0x8e, 0x02, 0x05, 0x05, 0x00, 0x03, 0x02, 0x00, 0xc4, 0x02, 0x02, 0x02, 0x95, 0x02, 0x05, 0x85, 0xaf, 0x02, 0x85, 0x06, 0x0e, 0x03, 0x01, 0x06, 0x42, 0x83, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x0b, 0x03, 0x00, 0x01, 0x0e, 0x03, 0x06, 0x07, 0x44, 0x03, 0x01, 0x02, 0x23, 0x03, 0x06, 0x05, 0x2e, 0x03, 0x05, 0x07, 0x89, 0x03, 0x01, 0x00, 0xc4, 0x03, 0x01, 0x02, 0x13, 0x04, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x8b, 0x04, 0x00, 0x08, 0x09, 0x05, 0x02, 0x00, 0xc4, 0x04, 0x02, 0x05, 0xcb, 0x84, 0x05, 0x00, 0x8c, 0x07, 0x07, 0x0e, 0xc2, 0x07, 0x00, 0x00, 0xb8, 0x03, 0x00, 0x80, 0x8c, 0x07, 0x00, 0x0e, 0xc2, 0x07, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0xb4, 0x07, 0x08, 0x00, 0x95, 0x07, 0x0f, 0x80, 0xaf, 0x07, 0x80, 0x06, 0x0c, 0x08, 0x00, 0x0e, 0x10, 0x04, 0x0f, 0x10, 0xcc, 0x04, 0x00, 0x02, 0xcd, 0x84, 0x06, 0x00, 0xb6, 0x04, 0x00, 0x00, 0x8b, 0x04, 0x00, 0x01, 0x8e, 0x04, 0x09, 0x09, 0x01, 0x85, 0xff, 0x7f, 0x80, 0x05, 0x06, 0x00, 0x0b, 0x06, 0x00, 0x01, 0x0e, 0x06, 0x0c, 0x0a, 0x44, 0x06, 0x01, 0x02, 0x80, 0x06, 0x05, 0x00, 0x00, 0x07, 0x04, 0x00, 0xc4, 0x04, 0x06, 0x01, 0xb4, 0x04, 0x08, 0x00, 0xbd, 0x04, 0x7f, 0x00, 0x38, 0x00, 0x00, 0x80, 0xc6, 0x82, 0x02, 0x00, 0x8b, 0x04, 0x00, 0x01, 0x8e, 0x04, 0x09, 0x0a, 0xc4, 0x04, 0x01, 0x02, 0x34, 0x05, 0x08, 0x00, 0xa8, 0x04, 0x09, 0x0a, 0xae, 0x04, 0x0a, 0x0c, 0x0b, 0x05, 0x00, 0x08, 0x80, 0x05, 0x08, 0x00, 0x44, 0x05, 0x02, 0x05, 0x4b, 0x85, 0x0d, 0x00, 0x15, 0x08, 0x0e, 0x7e, 0x2f, 0x07, 0x80, 0x07, 0x24, 0x08, 0x09, 0x10, 0xae, 0x04, 0x10, 0x08, 0x8b, 0x08, 0x00, 0x01, 0x8e, 0x08, 0x11, 0x0b, 0x00, 0x09, 0x02, 0x00, 0x80, 0x09, 0x0f, 0x00, 0xc4, 0x08, 0x03, 0x02, 0xa3, 0x08, 0x09, 0x11, 0xae, 0x04, 0x11, 0x07, 0x9c, 0x08, 0x11, 0x0c, 0xb0, 0x08, 0x0c, 0x0c, 0x22, 0x08, 0x10, 0x11, 0x2e, 0x08, 0x11, 0x06, 0x8b, 0x08, 0x00, 0x01, 0x8e, 0x08, 0x11, 0x0d, 0x00, 0x09, 0x02, 0x00, 0x80, 0x09, 0x10, 0x00, 0x15, 0x0a, 0x06, 0x82, 0x2f, 0x03, 0x82, 0x06, 0x80, 0x0a, 0x0f, 0x00, 0x00, 0x0b, 0x03, 0x00, 0x8b, 0x0b, 0x00, 0x01, 0x8e, 0x0b, 0x17, 0x0e, 0x00, 0x0c, 0x04, 0x00, 0xc4, 0x08, 0x08, 0x01, 0x4c, 0x05, 0x00, 0x02, 0x4d, 0x85, 0x0e, 0x00, 0x36, 0x05, 0x00, 0x00, 0xc6, 0x82, 0x02, 0x00, 0x46, 0x85, 0x01, 0x00, 0x8f, 0x04, 0x85, 0x66, 0x6f, 0x6e, 0x74, 0x04, 0x84, 0x67, 0x75, 0x69, 0x04, 0x8b, 0x46, 0x4f, 0x4e, 0x54, 0x5f, 0x53, 0x4d, 0x41, 0x4c, 0x4c, 0x04, 0x86, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x8b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x04, 0x8e, 0x67, 0x65, 0x74, 0x46, 0x6f, 0x6e, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x04, 0x82, 0x79, 0x04, 0x8a, 0x67, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x04, 0x87, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, 0x04, 0x89, 0x66, 0x69, 0x6c, 0x6c, 0x52, 0x65, 0x63, 0x74, 0x04, 0x89, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x04, 0x8d, 0x67, 0x65, 0x74, 0x54, 0x65, 0x78, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x89, 0x64, 0x72, 0x61, 0x77, 0x54, 0x65, 0x78, 0x74, 0x04, 0x8d, 0x53, 0x54, 0x59, 0x4c, 0x45, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x83, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; +static const unsigned char ui[] = {0x1b, 0x4c, 0x75, 0x61, 0x54, 0x00, 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a, 0x04, 0x04, 0x04, 0x78, 0x56, 0x00, 0x00, 0x00, 0x40, 0xb9, 0x43, 0x01, 0x80, 0x80, 0x80, 0x00, 0x01, 0x1d, 0x01, 0xbf, 0x51, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x13, 0x01, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x93, 0x01, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x02, 0x7f, 0x80, 0x01, 0x03, 0x7f, 0x80, 0x81, 0x03, 0x7f, 0x80, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x02, 0x04, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x82, 0xff, 0x7f, 0x01, 0x83, 0xff, 0x7f, 0x81, 0x83, 0xff, 0x7f, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x03, 0x04, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x82, 0xff, 0x7f, 0x01, 0x83, 0x3b, 0x80, 0x81, 0x03, 0x7f, 0x80, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x04, 0x04, 0x92, 0x81, 0x05, 0x06, 0x12, 0x01, 0x01, 0x03, 0x93, 0x01, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x82, 0x08, 0x80, 0x01, 0x83, 0x08, 0x80, 0x81, 0x83, 0x09, 0x80, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x02, 0x04, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x02, 0x75, 0x80, 0x01, 0x03, 0x75, 0x80, 0x81, 0x03, 0x75, 0x80, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x03, 0x04, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x82, 0x52, 0x80, 0x01, 0x83, 0x3a, 0x80, 0x81, 0x03, 0x7f, 0x80, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x04, 0x04, 0x92, 0x81, 0x05, 0x06, 0x12, 0x01, 0x07, 0x03, 0x93, 0x01, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x02, 0x7f, 0x80, 0x01, 0x03, 0x7f, 0x80, 0x81, 0x03, 0x7f, 0x80, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x02, 0x04, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x82, 0xff, 0x7f, 0x01, 0x83, 0xff, 0x7f, 0x81, 0x83, 0xff, 0x7f, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x03, 0x04, 0x13, 0x02, 0x00, 0x03, 0x52, 0x00, 0x00, 0x00, 0x81, 0x82, 0xff, 0x7f, 0x01, 0x83, 0xff, 0x7f, 0x81, 0x83, 0xff, 0x7f, 0x4e, 0x02, 0x03, 0x00, 0x92, 0x01, 0x04, 0x04, 0x92, 0x81, 0x05, 0x09, 0x12, 0x01, 0x08, 0x03, 0x93, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x93, 0x02, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x13, 0x03, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x93, 0x03, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x05, 0x04, 0x00, 0x00, 0x88, 0x04, 0x02, 0x00, 0x4f, 0x06, 0x00, 0x00, 0xcf, 0x86, 0x00, 0x00, 0x4f, 0x07, 0x01, 0x00, 0xcf, 0x87, 0x01, 0x00, 0x4f, 0x08, 0x02, 0x00, 0x12, 0x00, 0x0a, 0x10, 0x4f, 0x88, 0x02, 0x00, 0x12, 0x00, 0x0b, 0x10, 0x4f, 0x08, 0x03, 0x00, 0x12, 0x00, 0x0c, 0x10, 0x0b, 0x08, 0x00, 0x0d, 0x0e, 0x08, 0x10, 0x0e, 0x80, 0x08, 0x01, 0x00, 0x01, 0x89, 0x0f, 0x80, 0x44, 0x08, 0x03, 0x02, 0x80, 0x08, 0x0f, 0x00, 0x42, 0x08, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x14, 0x89, 0x10, 0x0f, 0x03, 0x0a, 0x08, 0x00, 0x44, 0x09, 0x03, 0x02, 0x42, 0x89, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x03, 0x89, 0x08, 0x00, 0xc4, 0x08, 0x02, 0x01, 0xcf, 0x88, 0x03, 0x00, 0x0b, 0x09, 0x00, 0x12, 0x0e, 0x09, 0x12, 0x13, 0xcf, 0x09, 0x04, 0x00, 0x44, 0x09, 0x02, 0x01, 0x13, 0x09, 0x00, 0x0a, 0x52, 0x00, 0x00, 0x00, 0x83, 0x09, 0x0a, 0x00, 0x03, 0x8a, 0x0a, 0x00, 0x83, 0x0a, 0x0b, 0x00, 0x03, 0x8b, 0x0b, 0x00, 0x83, 0x0b, 0x0c, 0x00, 0x03, 0x8c, 0x0c, 0x00, 0x83, 0x0c, 0x0d, 0x00, 0x03, 0x8d, 0x0d, 0x00, 0x83, 0x0d, 0x0e, 0x00, 0x03, 0x8e, 0x0e, 0x00, 0x4e, 0x09, 0x0a, 0x00, 0xcf, 0x89, 0x04, 0x00, 0x4f, 0x0a, 0x05, 0x00, 0xcf, 0x8a, 0x05, 0x00, 0x12, 0x00, 0x1e, 0x15, 0xcf, 0x0a, 0x06, 0x00, 0x12, 0x00, 0x1f, 0x15, 0xcf, 0x8a, 0x06, 0x00, 0x12, 0x00, 0x20, 0x15, 0xcf, 0x0a, 0x07, 0x00, 0x12, 0x00, 0x21, 0x15, 0xcf, 0x8a, 0x07, 0x00, 0x12, 0x00, 0x22, 0x15, 0xcf, 0x0a, 0x08, 0x00, 0x12, 0x00, 0x23, 0x15, 0xcf, 0x8a, 0x08, 0x00, 0x12, 0x00, 0x24, 0x15, 0xcf, 0x0a, 0x09, 0x00, 0x12, 0x00, 0x25, 0x15, 0xcf, 0x8a, 0x09, 0x00, 0x12, 0x00, 0x26, 0x15, 0xcf, 0x0a, 0x0a, 0x00, 0x12, 0x00, 0x27, 0x15, 0xcf, 0x8a, 0x0a, 0x00, 0x12, 0x00, 0x28, 0x15, 0x93, 0x0a, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x92, 0x0a, 0x29, 0x15, 0x4f, 0x0b, 0x0b, 0x00, 0x80, 0x05, 0x16, 0x00, 0x4f, 0x8b, 0x0b, 0x00, 0x12, 0x00, 0x2a, 0x16, 0x4f, 0x0b, 0x0c, 0x00, 0x92, 0x0a, 0x2b, 0x16, 0x4f, 0x8b, 0x0c, 0x00, 0x92, 0x0a, 0x2c, 0x16, 0x4f, 0x0b, 0x0d, 0x00, 0xcf, 0x8b, 0x0d, 0x00, 0x4f, 0x0c, 0x0e, 0x00, 0xcf, 0x8c, 0x0e, 0x00, 0x92, 0x0a, 0x2d, 0x19, 0xcf, 0x0c, 0x0f, 0x00, 0x92, 0x0a, 0x2e, 0x19, 0xcf, 0x8c, 0x0f, 0x00, 0x92, 0x0a, 0x2f, 0x19, 0x93, 0x0c, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x92, 0x8c, 0x2f, 0x30, 0x92, 0x8c, 0x2d, 0x30, 0x92, 0x8c, 0x31, 0x30, 0x92, 0x8c, 0x32, 0x30, 0x4f, 0x0d, 0x10, 0x00, 0xcf, 0x8d, 0x10, 0x00, 0x92, 0x0a, 0x33, 0x1b, 0x46, 0x80, 0x02, 0x01, 0xc6, 0x8d, 0x01, 0x01, 0xb4, 0x04, 0x8c, 0x2f, 0x2e, 0x6c, 0x75, 0x61, 0x2f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x04, 0x86, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x04, 0x8b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x04, 0x86, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x87, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x04, 0x87, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x03, 0x06, 0x00, 0x00, 0x00, 0x04, 0x85, 0x64, 0x61, 0x72, 0x6b, 0x04, 0x85, 0x6d, 0x6f, 0x6e, 0x6f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x89, 0x67, 0x65, 0x74, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x04, 0x8b, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x04, 0x89, 0x73, 0x65, 0x74, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x04, 0x83, 0x66, 0x73, 0x04, 0x89, 0x72, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x04, 0x86, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x04, 0x8d, 0x5e, 0x25, 0x73, 0x2a, 0x28, 0x2e, 0x2d, 0x29, 0x25, 0x73, 0x2a, 0x24, 0x04, 0x86, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x8b, 0x73, 0x65, 0x74, 0x50, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x04, 0x86, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x85, 0x66, 0x69, 0x6c, 0x6c, 0x04, 0x87, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x04, 0x85, 0x66, 0x61, 0x63, 0x65, 0x04, 0x8c, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x46, 0x61, 0x63, 0x65, 0x04, 0x8d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x8b, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x87, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x04, 0x85, 0x66, 0x6f, 0x6e, 0x74, 0x04, 0x8a, 0x74, 0x65, 0x78, 0x74, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x04, 0x84, 0x62, 0x6f, 0x78, 0x04, 0x89, 0x63, 0x61, 0x72, 0x64, 0x53, 0x69, 0x64, 0x65, 0x04, 0x87, 0x73, 0x70, 0x61, 0x63, 0x65, 0x72, 0x04, 0x85, 0x74, 0x65, 0x78, 0x74, 0x04, 0x86, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x04, 0x87, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x04, 0x87, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x04, 0x88, 0x73, 0x65, 0x74, 0x54, 0x65, 0x78, 0x74, 0x04, 0x8b, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x04, 0x88, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x04, 0x86, 0x72, 0x65, 0x73, 0x65, 0x74, 0x04, 0x88, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x04, 0x87, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x04, 0x89, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x04, 0x85, 0x64, 0x72, 0x61, 0x77, 0x04, 0x85, 0x64, 0x6f, 0x77, 0x6e, 0x04, 0x85, 0x6d, 0x6f, 0x76, 0x65, 0x04, 0x83, 0x75, 0x70, 0x11, 0x04, 0x85, 0x6c, 0x65, 0x66, 0x74, 0x04, 0x86, 0x72, 0x69, 0x67, 0x68, 0x74, 0x04, 0x87, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x81, 0x01, 0x00, 0x00, 0xa2, 0x80, 0xbd, 0xc1, 0x03, 0x00, 0x0c, 0x98, 0x93, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x80, 0x81, 0x02, 0x01, 0x80, 0x01, 0x03, 0x00, 0x80, 0x4a, 0x82, 0x07, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x0e, 0x04, 0x08, 0x01, 0x8c, 0x04, 0x00, 0x07, 0x0c, 0x05, 0x01, 0x07, 0x8c, 0x05, 0x00, 0x07, 0x23, 0x05, 0x0a, 0x0b, 0x2e, 0x05, 0x0b, 0x07, 0x24, 0x05, 0x0a, 0x02, 0x2e, 0x05, 0x02, 0x08, 0xa2, 0x04, 0x09, 0x0a, 0xae, 0x04, 0x0a, 0x06, 0x96, 0x04, 0x09, 0x02, 0xb0, 0x04, 0x02, 0x06, 0x44, 0x04, 0x02, 0x02, 0x90, 0x01, 0x07, 0x08, 0x49, 0x02, 0x08, 0x00, 0xc8, 0x01, 0x02, 0x00, 0x47, 0x02, 0x01, 0x00, 0x83, 0x04, 0x85, 0x6d, 0x61, 0x74, 0x68, 0x04, 0x86, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x13, 0x00, 0x00, 0x00, 0x3f, 0x81, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc3, 0xc5, 0x01, 0x00, 0x05, 0x88, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x01, 0x0d, 0x01, 0x00, 0x01, 0x8d, 0x01, 0x00, 0x02, 0x0d, 0x02, 0x00, 0x03, 0xc5, 0x00, 0x04, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x01, 0x00, 0x82, 0x04, 0x84, 0x67, 0x75, 0x69, 0x04, 0x86, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x81, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc7, 0xd4, 0x01, 0x00, 0x0a, 0xb1, 0x8e, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x01, 0x8e, 0x01, 0x00, 0x02, 0x13, 0x02, 0x05, 0x00, 0x52, 0x00, 0x00, 0x00, 0x89, 0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0xc4, 0x02, 0x02, 0x02, 0x12, 0x02, 0x00, 0x05, 0x89, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0xc4, 0x02, 0x02, 0x02, 0x12, 0x02, 0x01, 0x05, 0x89, 0x02, 0x00, 0x00, 0x09, 0x03, 0x01, 0x00, 0x80, 0x03, 0x02, 0x00, 0x00, 0x04, 0x01, 0x00, 0x83, 0x04, 0x02, 0x00, 0x44, 0x03, 0x04, 0x00, 0xc4, 0x02, 0x00, 0x02, 0x12, 0x02, 0x03, 0x05, 0x89, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0xc4, 0x02, 0x02, 0x02, 0x12, 0x02, 0x02, 0x05, 0x89, 0x02, 0x00, 0x00, 0x09, 0x03, 0x01, 0x00, 0x80, 0x03, 0x01, 0x00, 0x00, 0x04, 0x02, 0x00, 0x83, 0x04, 0x03, 0x00, 0x44, 0x03, 0x04, 0x00, 0xc4, 0x02, 0x00, 0x02, 0x12, 0x02, 0x05, 0x05, 0x89, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0xc4, 0x02, 0x02, 0x02, 0x12, 0x02, 0x07, 0x05, 0x89, 0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0xc4, 0x02, 0x02, 0x02, 0x12, 0x02, 0x08, 0x05, 0x89, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0xc4, 0x02, 0x02, 0x02, 0x12, 0x02, 0x09, 0x05, 0x8e, 0x02, 0x00, 0x0a, 0x12, 0x02, 0x0a, 0x05, 0x48, 0x02, 0x02, 0x00, 0x47, 0x02, 0x01, 0x00, 0x8b, 0x04, 0x8b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x04, 0x86, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x87, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x04, 0x86, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x13, 0x66, 0x66, 0xe6, 0x3e, 0x04, 0x85, 0x66, 0x61, 0x63, 0x65, 0x13, 0x0a, 0xd7, 0xa3, 0x3d, 0x04, 0x8c, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x46, 0x61, 0x63, 0x65, 0x04, 0x8d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x8b, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x87, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x82, 0x01, 0x0d, 0x00, 0x01, 0x0c, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xd6, 0xd9, 0x01, 0x00, 0x04, 0x8f, 0x89, 0x00, 0x01, 0x00, 0x8c, 0x00, 0x01, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0xc3, 0x80, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x83, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, 0x89, 0x01, 0x00, 0x00, 0x09, 0x01, 0x01, 0x00, 0x0c, 0x01, 0x02, 0x03, 0xc4, 0x00, 0x02, 0x02, 0x0f, 0x01, 0x01, 0x01, 0xc7, 0x00, 0x01, 0x00, 0x82, 0x04, 0x86, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x04, 0x86, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x84, 0x01, 0x09, 0x00, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xdc, 0xde, 0x00, 0x00, 0x02, 0x83, 0x09, 0x00, 0x00, 0x00, 0x48, 0x00, 0x02, 0x00, 0x47, 0x00, 0x01, 0x00, 0x80, 0x81, 0x01, 0x09, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe1, 0xe6, 0x00, 0x00, 0x08, 0x93, 0x13, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x09, 0x01, 0x01, 0x00, 0xc4, 0x00, 0x02, 0x05, 0xcb, 0x00, 0x02, 0x00, 0x34, 0x03, 0x00, 0x00, 0x15, 0x03, 0x06, 0x80, 0x2f, 0x03, 0x80, 0x06, 0x10, 0x00, 0x06, 0x05, 0xcc, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x03, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x00, 0x02, 0x01, 0x46, 0x80, 0x02, 0x00, 0xc6, 0x80, 0x01, 0x00, 0x83, 0x04, 0x86, 0x70, 0x61, 0x69, 0x72, 0x73, 0x04, 0x86, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x04, 0x85, 0x73, 0x6f, 0x72, 0x74, 0x82, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xeb, 0xf6, 0x01, 0x00, 0x05, 0xa6, 0x89, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x01, 0x00, 0xc2, 0x80, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x88, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0xc6, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x01, 0x01, 0x8e, 0x00, 0x01, 0x02, 0x09, 0x01, 0x02, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc4, 0x00, 0x03, 0x03, 0xc2, 0x80, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x88, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0xc6, 0x01, 0x03, 0x00, 0x89, 0x01, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0xc4, 0x01, 0x02, 0x01, 0x89, 0x01, 0x04, 0x00, 0xc2, 0x01, 0x00, 0x00, 0xb8, 0x05, 0x00, 0x80, 0x89, 0x01, 0x05, 0x00, 0x0b, 0x02, 0x04, 0x03, 0xc4, 0x01, 0x02, 0x01, 0x8b, 0x01, 0x01, 0x04, 0x8e, 0x01, 0x03, 0x05, 0x0b, 0x02, 0x06, 0x06, 0x0e, 0x02, 0x04, 0x07, 0xc4, 0x01, 0x02, 0x01, 0x8b, 0x01, 0x01, 0x08, 0x8e, 0x01, 0x03, 0x09, 0x0b, 0x02, 0x04, 0x03, 0xc4, 0x01, 0x02, 0x01, 0x87, 0x01, 0x00, 0x00, 0xc8, 0x01, 0x02, 0x00, 0xc7, 0x01, 0x01, 0x00, 0x8a, 0x04, 0x8e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x04, 0x83, 0x66, 0x73, 0x04, 0x8a, 0x77, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x04, 0x85, 0x72, 0x6f, 0x6f, 0x74, 0x04, 0x84, 0x67, 0x75, 0x69, 0x04, 0x86, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x04, 0x86, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x04, 0x8b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x8b, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x87, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x0f, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x0b, 0x00, 0x01, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xfb, 0xfe, 0x00, 0x00, 0x04, 0x90, 0x13, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x93, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x8a, 0x01, 0x03, 0x00, 0x0a, 0x01, 0x02, 0x00, 0x8a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x47, 0x00, 0x01, 0x00, 0x80, 0x85, 0x01, 0x03, 0x00, 0x01, 0x04, 0x00, 0x01, 0x05, 0x00, 0x01, 0x06, 0x00, 0x01, 0x07, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0x80, 0x01, 0x83, 0x05, 0x00, 0x0c, 0x8c, 0x89, 0x02, 0x00, 0x00, 0x8c, 0x02, 0x05, 0x00, 0xc2, 0x02, 0x00, 0x00, 0x38, 0x03, 0x00, 0x80, 0x00, 0x03, 0x05, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x80, 0x04, 0x02, 0x00, 0x00, 0x05, 0x03, 0x00, 0x80, 0x05, 0x04, 0x00, 0x44, 0x03, 0x06, 0x01, 0x47, 0x03, 0x01, 0x00, 0x80, 0x81, 0x01, 0x06, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0x8a, 0x01, 0x95, 0x02, 0x00, 0x0b, 0xa0, 0x13, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0x0b, 0x02, 0x00, 0x00, 0x89, 0x02, 0x01, 0x00, 0x44, 0x02, 0x02, 0x05, 0x4b, 0x02, 0x03, 0x00, 0x0c, 0x05, 0x01, 0x09, 0x3c, 0x85, 0x01, 0x00, 0x38, 0x01, 0x00, 0x80, 0x0c, 0x05, 0x01, 0x09, 0x87, 0x01, 0x00, 0x00, 0x10, 0x01, 0x09, 0x0a, 0x4c, 0x02, 0x00, 0x02, 0x4d, 0x02, 0x04, 0x00, 0x36, 0x02, 0x00, 0x00, 0x0e, 0x02, 0x01, 0x02, 0x3c, 0x82, 0x01, 0x00, 0x38, 0x02, 0x00, 0x80, 0x0e, 0x02, 0x01, 0x02, 0x8e, 0x02, 0x01, 0x02, 0x87, 0x01, 0x00, 0x00, 0x12, 0x01, 0x03, 0x05, 0x12, 0x01, 0x02, 0x04, 0xc2, 0x01, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x0b, 0x02, 0x00, 0x04, 0x0e, 0x02, 0x04, 0x05, 0x80, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x44, 0x02, 0x03, 0x01, 0x46, 0x82, 0x01, 0x00, 0x86, 0x04, 0x87, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, 0x00, 0x04, 0x8b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x04, 0x85, 0x66, 0x69, 0x6c, 0x6c, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x89, 0x73, 0x65, 0x74, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x82, 0x00, 0x00, 0x00, 0x01, 0x12, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0x97, 0x01, 0xad, 0x02, 0x00, 0x0d, 0xcc, 0x42, 0x80, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x13, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x0b, 0x01, 0x01, 0x00, 0x44, 0x01, 0x01, 0x01, 0x13, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00, 0xc4, 0x01, 0x02, 0x05, 0xcb, 0x01, 0x01, 0x00, 0x10, 0x01, 0x07, 0x08, 0x10, 0x80, 0x07, 0x02, 0xcc, 0x01, 0x00, 0x02, 0xcd, 0x01, 0x02, 0x00, 0xb6, 0x01, 0x00, 0x00, 0x12, 0x00, 0x03, 0x01, 0x8e, 0x01, 0x00, 0x05, 0xbc, 0x01, 0x02, 0x00, 0x38, 0x03, 0x00, 0x80, 0x8e, 0x01, 0x00, 0x06, 0xbc, 0x01, 0x02, 0x00, 0xb8, 0x01, 0x00, 0x80, 0x8e, 0x01, 0x00, 0x07, 0xbc, 0x01, 0x02, 0x00, 0x38, 0x00, 0x00, 0x80, 0x86, 0x01, 0x00, 0x00, 0x87, 0x01, 0x00, 0x00, 0x12, 0x00, 0x04, 0x03, 0x8b, 0x01, 0x02, 0x08, 0x8e, 0x01, 0x03, 0x09, 0x08, 0x02, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xc4, 0x01, 0x03, 0x02, 0x0b, 0x02, 0x02, 0x01, 0x80, 0x02, 0x02, 0x00, 0x44, 0x02, 0x02, 0x05, 0x4b, 0x82, 0x02, 0x00, 0x0b, 0x05, 0x02, 0x08, 0x0e, 0x05, 0x0a, 0x0a, 0x80, 0x05, 0x03, 0x00, 0x00, 0x06, 0x09, 0x00, 0x44, 0x05, 0x03, 0x01, 0x4c, 0x02, 0x00, 0x02, 0x4d, 0x82, 0x03, 0x00, 0x36, 0x02, 0x00, 0x00, 0x09, 0x02, 0x03, 0x00, 0x80, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x44, 0x02, 0x03, 0x01, 0x09, 0x02, 0x04, 0x00, 0x8e, 0x02, 0x00, 0x05, 0x10, 0x02, 0x03, 0x05, 0x09, 0x02, 0x05, 0x00, 0x8e, 0x02, 0x00, 0x06, 0x10, 0x02, 0x03, 0x05, 0x09, 0x02, 0x06, 0x00, 0x8e, 0x02, 0x00, 0x07, 0x10, 0x02, 0x03, 0x05, 0x09, 0x02, 0x07, 0x00, 0x8e, 0x02, 0x00, 0x0b, 0x10, 0x02, 0x03, 0x05, 0x09, 0x02, 0x08, 0x00, 0x8e, 0x02, 0x00, 0x0c, 0xbc, 0x02, 0x0d, 0x00, 0x38, 0x00, 0x00, 0x80, 0x86, 0x02, 0x00, 0x00, 0x87, 0x02, 0x00, 0x00, 0x10, 0x02, 0x03, 0x05, 0xc6, 0x81, 0x02, 0x00, 0x46, 0x82, 0x01, 0x00, 0x8e, 0x04, 0x86, 0x72, 0x65, 0x73, 0x65, 0x74, 0x04, 0x87, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, 0x00, 0x04, 0x85, 0x74, 0x79, 0x70, 0x65, 0x04, 0x8c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x04, 0x89, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x04, 0x88, 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x04, 0x89, 0x6f, 0x6e, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x87, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x04, 0x87, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x04, 0x86, 0x70, 0x61, 0x69, 0x6e, 0x74, 0x04, 0x8c, 0x70, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x01, 0x89, 0x01, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x13, 0x00, 0x01, 0x03, 0x00, 0x01, 0x04, 0x00, 0x01, 0x05, 0x00, 0x01, 0x06, 0x00, 0x01, 0x07, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0xb1, 0x01, 0xb3, 0x01, 0x00, 0x04, 0x86, 0x89, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0xc5, 0x00, 0x03, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x01, 0x00, 0x81, 0x04, 0x84, 0x62, 0x6f, 0x78, 0x81, 0x01, 0x14, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0xbd, 0x01, 0xc3, 0x04, 0x00, 0x0b, 0xbc, 0x0b, 0x02, 0x00, 0x00, 0x0e, 0x02, 0x04, 0x01, 0x44, 0x02, 0x01, 0x02, 0x8b, 0x02, 0x00, 0x00, 0x8e, 0x02, 0x05, 0x02, 0xc4, 0x02, 0x01, 0x02, 0xbb, 0x02, 0x04, 0x00, 0x38, 0x01, 0x00, 0x80, 0x01, 0x82, 0x01, 0x80, 0x42, 0x82, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x01, 0x02, 0x01, 0x80, 0x8b, 0x02, 0x00, 0x03, 0x8e, 0x02, 0x05, 0x04, 0x27, 0x03, 0x00, 0x04, 0x2e, 0x00, 0x04, 0x0b, 0xc4, 0x02, 0x02, 0x02, 0x0b, 0x03, 0x00, 0x00, 0x0e, 0x03, 0x06, 0x01, 0x44, 0x03, 0x01, 0x02, 0x98, 0x03, 0x01, 0x05, 0xb0, 0x80, 0x05, 0x08, 0x23, 0x03, 0x06, 0x07, 0x2e, 0x03, 0x07, 0x07, 0x95, 0x03, 0x04, 0x7e, 0x2f, 0x02, 0x80, 0x07, 0xa4, 0x03, 0x07, 0x02, 0xae, 0x03, 0x02, 0x08, 0x23, 0x03, 0x06, 0x07, 0x2e, 0x03, 0x07, 0x07, 0x28, 0x03, 0x06, 0x04, 0x2e, 0x03, 0x04, 0x0c, 0x8b, 0x03, 0x00, 0x00, 0x8e, 0x03, 0x07, 0x02, 0xc4, 0x03, 0x01, 0x02, 0x18, 0x04, 0x01, 0x05, 0xb0, 0x80, 0x05, 0x08, 0xa3, 0x03, 0x07, 0x08, 0xae, 0x03, 0x08, 0x07, 0x43, 0x84, 0x03, 0x00, 0x38, 0x00, 0x00, 0x80, 0x01, 0x84, 0xff, 0x7f, 0xa3, 0x03, 0x07, 0x08, 0xae, 0x03, 0x08, 0x07, 0x15, 0x04, 0x05, 0x7e, 0xaf, 0x02, 0x80, 0x07, 0x24, 0x04, 0x08, 0x02, 0x2e, 0x04, 0x02, 0x08, 0xa3, 0x03, 0x07, 0x08, 0xae, 0x03, 0x08, 0x07, 0xa8, 0x03, 0x07, 0x05, 0xae, 0x03, 0x05, 0x0c, 0x0b, 0x04, 0x00, 0x03, 0x0e, 0x04, 0x08, 0x06, 0x80, 0x04, 0x06, 0x00, 0x00, 0x05, 0x07, 0x00, 0x44, 0x04, 0x03, 0x02, 0x80, 0x04, 0x04, 0x00, 0x46, 0x04, 0x03, 0x00, 0x47, 0x04, 0x01, 0x00, 0x87, 0x04, 0x84, 0x67, 0x75, 0x69, 0x04, 0x89, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x04, 0x8a, 0x67, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x04, 0x85, 0x6d, 0x61, 0x74, 0x68, 0x04, 0x85, 0x63, 0x65, 0x69, 0x6c, 0x03, 0x02, 0x00, 0x00, 0x00, 0x04, 0x84, 0x6d, 0x69, 0x6e, 0x81, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0xc7, 0x01, 0xca, 0x01, 0x00, 0x04, 0x90, 0x42, 0x80, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x93, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x89, 0x00, 0x00, 0x00, 0x13, 0x01, 0x02, 0x00, 0x52, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x12, 0x01, 0x00, 0x03, 0x8e, 0x01, 0x00, 0x01, 0x12, 0x01, 0x01, 0x03, 0x83, 0x01, 0x01, 0x00, 0xc5, 0x00, 0x03, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x01, 0x00, 0x83, 0x04, 0x82, 0x77, 0x04, 0x82, 0x68, 0x04, 0x84, 0x62, 0x6f, 0x78, 0x81, 0x01, 0x14, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0xcf, 0x01, 0xd4, 0x02, 0x00, 0x05, 0x8f, 0xc2, 0x80, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x13, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x02, 0x00, 0x92, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x01, 0x02, 0x92, 0x80, 0x02, 0x03, 0x92, 0x00, 0x01, 0x02, 0x09, 0x01, 0x00, 0x00, 0x80, 0x01, 0x01, 0x00, 0x03, 0x02, 0x02, 0x00, 0x45, 0x01, 0x03, 0x00, 0x46, 0x01, 0x00, 0x00, 0x47, 0x01, 0x01, 0x00, 0x85, 0x04, 0x86, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x04, 0x8a, 0x74, 0x65, 0x78, 0x74, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x04, 0x86, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x00, 0x04, 0x85, 0x74, 0x65, 0x78, 0x74, 0x81, 0x01, 0x14, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0xd9, 0x01, 0xe6, 0x02, 0x00, 0x08, 0xc9, 0xc2, 0x80, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x13, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x02, 0x00, 0x0e, 0x01, 0x01, 0x00, 0x42, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x0b, 0x01, 0x00, 0x01, 0x0e, 0x01, 0x02, 0x02, 0x8e, 0x01, 0x01, 0x03, 0xc2, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x8b, 0x01, 0x00, 0x01, 0x8e, 0x01, 0x03, 0x04, 0x0e, 0x02, 0x01, 0x05, 0x42, 0x02, 0x00, 0x00, 0x38, 0x10, 0x00, 0x80, 0x0b, 0x02, 0x00, 0x01, 0x0e, 0x02, 0x04, 0x06, 0x80, 0x02, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x03, 0x03, 0x00, 0x44, 0x02, 0x04, 0x02, 0x8e, 0x02, 0x01, 0x05, 0xba, 0x02, 0x04, 0x00, 0xb8, 0x0b, 0x00, 0x80, 0x34, 0x02, 0x00, 0x00, 0x40, 0x02, 0x80, 0x00, 0x38, 0x08, 0x00, 0x80, 0x0b, 0x02, 0x00, 0x01, 0x0e, 0x02, 0x04, 0x06, 0x80, 0x02, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x83, 0x83, 0x03, 0x00, 0x35, 0x03, 0x02, 0x00, 0x80, 0x03, 0x03, 0x00, 0x44, 0x02, 0x04, 0x02, 0x8e, 0x02, 0x01, 0x05, 0xba, 0x02, 0x04, 0x00, 0xb8, 0x02, 0x00, 0x80, 0x14, 0x82, 0x00, 0x08, 0x01, 0x03, 0x00, 0x80, 0x81, 0x83, 0xfe, 0x7f, 0x44, 0x02, 0x04, 0x02, 0x00, 0x00, 0x04, 0x00, 0xb8, 0xf5, 0xff, 0x7f, 0x00, 0x02, 0x00, 0x00, 0x83, 0x82, 0x03, 0x00, 0x35, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0b, 0x02, 0x00, 0x01, 0x0e, 0x02, 0x04, 0x06, 0x80, 0x02, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x03, 0x03, 0x00, 0x44, 0x02, 0x04, 0x02, 0x92, 0x00, 0x09, 0x04, 0x0b, 0x02, 0x00, 0x01, 0x0e, 0x02, 0x04, 0x0b, 0x80, 0x02, 0x02, 0x00, 0x00, 0x03, 0x03, 0x00, 0x44, 0x02, 0x03, 0x02, 0x92, 0x00, 0x0a, 0x04, 0x00, 0x02, 0x02, 0x00, 0x92, 0x80, 0x05, 0x0c, 0x92, 0x00, 0x00, 0x04, 0x0b, 0x02, 0x01, 0x0d, 0x80, 0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x45, 0x02, 0x03, 0x00, 0x46, 0x02, 0x00, 0x00, 0x47, 0x02, 0x01, 0x00, 0x8e, 0x04, 0x85, 0x66, 0x6f, 0x6e, 0x74, 0x04, 0x84, 0x67, 0x75, 0x69, 0x04, 0x88, 0x46, 0x4f, 0x4e, 0x54, 0x5f, 0x55, 0x49, 0x04, 0x86, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x04, 0x8d, 0x53, 0x54, 0x59, 0x4c, 0x45, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x04, 0x84, 0x66, 0x69, 0x74, 0x04, 0x8d, 0x67, 0x65, 0x74, 0x54, 0x65, 0x78, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x04, 0x82, 0x7e, 0x04, 0x84, 0x73, 0x75, 0x62, 0x04, 0x82, 0x77, 0x04, 0x82, 0x68, 0x04, 0x8e, 0x67, 0x65, 0x74, 0x46, 0x6f, 0x6e, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x04, 0x85, 0x74, 0x65, 0x78, 0x74, 0x82, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0xea, 0x01, 0xf3, 0x01, 0x00, 0x08, 0xa7, 0x42, 0x80, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x93, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x8e, 0x00, 0x00, 0x00, 0xc2, 0x80, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x81, 0x80, 0x03, 0x80, 0x12, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x01, 0xc2, 0x80, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x83, 0x00, 0x01, 0x00, 0x12, 0x00, 0x01, 0x01, 0x8e, 0x00, 0x00, 0x03, 0x0e, 0x01, 0x00, 0x04, 0x12, 0x80, 0x03, 0x05, 0x89, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x83, 0x02, 0x03, 0x00, 0xc4, 0x01, 0x03, 0x02, 0xc2, 0x00, 0x00, 0x00, 0x38, 0x06, 0x00, 0x80, 0x0b, 0x02, 0x01, 0x07, 0x0e, 0x02, 0x04, 0x08, 0x80, 0x02, 0x03, 0x00, 0x13, 0x03, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x12, 0x83, 0x09, 0x0a, 0x12, 0x03, 0x03, 0x01, 0xc3, 0x83, 0x02, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x8b, 0x03, 0x01, 0x0b, 0x8e, 0x03, 0x07, 0x0c, 0x12, 0x03, 0x04, 0x07, 0x44, 0x02, 0x03, 0x01, 0xc8, 0x01, 0x02, 0x00, 0x47, 0x02, 0x01, 0x00, 0x8d, 0x04, 0x84, 0x70, 0x61, 0x64, 0x04, 0x86, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x04, 0x87, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x04, 0x86, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x04, 0x85, 0x66, 0x6f, 0x6e, 0x74, 0x00, 0x04, 0x87, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x87, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x04, 0x85, 0x74, 0x79, 0x70, 0x65, 0x04, 0x85, 0x74, 0x65, 0x78, 0x74, 0x04, 0x84, 0x67, 0x75, 0x69, 0x04, 0x88, 0x46, 0x4f, 0x4e, 0x54, 0x5f, 0x55, 0x49, 0x82, 0x01, 0x14, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0xf7, 0x01, 0xf9, 0x01, 0x00, 0x04, 0x86, 0x89, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0xc5, 0x00, 0x03, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x01, 0x00, 0x81, 0x04, 0x87, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x81, 0x01, 0x14, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0xfd, 0x02, 0x81, 0x02, 0x00, 0x05, 0x91, 0x0b, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x02, 0x01, 0x80, 0x01, 0x00, 0x00, 0x44, 0x01, 0x02, 0x02, 0x39, 0x01, 0x01, 0x00, 0x38, 0x00, 0x00, 0x80, 0x47, 0x01, 0x01, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x02, 0x02, 0x80, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x44, 0x01, 0x03, 0x01, 0x0b, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x02, 0x03, 0x80, 0x01, 0x00, 0x00, 0x44, 0x01, 0x02, 0x01, 0x47, 0x01, 0x01, 0x00, 0x84, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x89, 0x67, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x04, 0x89, 0x73, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x04, 0x8b, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x81, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0x84, 0x02, 0x86, 0x01, 0x00, 0x03, 0x85, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x00, 0x02, 0x01, 0xc7, 0x00, 0x01, 0x00, 0x82, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x8b, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x81, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0x8a, 0x02, 0xa1, 0x01, 0x00, 0x07, 0xeb, 0x93, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x42, 0x81, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x03, 0x81, 0x00, 0x00, 0x92, 0x00, 0x00, 0x02, 0x92, 0x80, 0x02, 0x03, 0x92, 0x80, 0x04, 0x05, 0x0e, 0x01, 0x00, 0x06, 0x42, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x0b, 0x01, 0x00, 0x07, 0x0e, 0x01, 0x02, 0x06, 0x92, 0x00, 0x06, 0x02, 0x0e, 0x01, 0x00, 0x08, 0x42, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x0b, 0x01, 0x00, 0x07, 0x0e, 0x01, 0x02, 0x09, 0x92, 0x00, 0x08, 0x02, 0x0b, 0x01, 0x00, 0x0a, 0x8e, 0x01, 0x00, 0x0b, 0x44, 0x01, 0x02, 0x00, 0xce, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x0c, 0x42, 0x01, 0x00, 0x00, 0xb8, 0x05, 0x00, 0x80, 0x34, 0x01, 0x01, 0x00, 0x15, 0x01, 0x02, 0x80, 0x2f, 0x01, 0x80, 0x06, 0x8b, 0x01, 0x00, 0x0a, 0x0e, 0x02, 0x00, 0x0c, 0x93, 0x02, 0x01, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0b, 0x03, 0x00, 0x07, 0x0e, 0x03, 0x06, 0x09, 0x92, 0x02, 0x0d, 0x06, 0xc4, 0x01, 0x03, 0x02, 0x90, 0x00, 0x02, 0x03, 0x13, 0x01, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x12, 0x81, 0x0e, 0x0f, 0x12, 0x81, 0x04, 0x10, 0x12, 0x81, 0x11, 0x12, 0x8e, 0x01, 0x00, 0x13, 0xbc, 0x81, 0x14, 0x00, 0x38, 0x07, 0x00, 0x80, 0xb4, 0x01, 0x02, 0x00, 0x95, 0x01, 0x03, 0x80, 0xaf, 0x01, 0x80, 0x06, 0x0b, 0x02, 0x00, 0x15, 0x93, 0x02, 0x02, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x00, 0x13, 0x42, 0x83, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x03, 0x83, 0x09, 0x00, 0x92, 0x02, 0x16, 0x06, 0x0e, 0x03, 0x00, 0x18, 0x92, 0x02, 0x17, 0x06, 0x44, 0x02, 0x02, 0x02, 0x10, 0x01, 0x03, 0x04, 0xb4, 0x01, 0x02, 0x00, 0x95, 0x01, 0x03, 0x80, 0xaf, 0x01, 0x80, 0x06, 0x0b, 0x02, 0x00, 0x15, 0x93, 0x02, 0x02, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x00, 0x19, 0x42, 0x83, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x03, 0x83, 0x0c, 0x00, 0x92, 0x02, 0x16, 0x06, 0x0e, 0x03, 0x00, 0x1a, 0x92, 0x02, 0x17, 0x06, 0x44, 0x02, 0x02, 0x02, 0x10, 0x01, 0x03, 0x04, 0xb4, 0x01, 0x01, 0x00, 0x95, 0x01, 0x03, 0x80, 0xaf, 0x01, 0x80, 0x06, 0x0b, 0x02, 0x00, 0x1b, 0x80, 0x02, 0x02, 0x00, 0x44, 0x02, 0x02, 0x02, 0x90, 0x00, 0x03, 0x04, 0x8b, 0x01, 0x00, 0x1b, 0x13, 0x02, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, 0x93, 0x02, 0x02, 0x00, 0x52, 0x00, 0x00, 0x00, 0x92, 0x82, 0x1d, 0x1e, 0x92, 0x82, 0x1f, 0x1e, 0x12, 0x02, 0x1c, 0x05, 0x12, 0x82, 0x00, 0x20, 0x12, 0x82, 0x21, 0x20, 0x12, 0x82, 0x22, 0x0f, 0x12, 0x82, 0x23, 0x24, 0x12, 0x82, 0x11, 0x24, 0x8e, 0x02, 0x00, 0x25, 0x12, 0x02, 0x17, 0x05, 0x8b, 0x02, 0x00, 0x1b, 0x00, 0x03, 0x01, 0x00, 0xc4, 0x02, 0x02, 0x00, 0x4e, 0x02, 0x00, 0x00, 0xc5, 0x01, 0x02, 0x00, 0xc6, 0x01, 0x00, 0x00, 0xc7, 0x01, 0x01, 0x00, 0xa6, 0x04, 0x82, 0x77, 0x13, 0x9a, 0x99, 0x59, 0x3f, 0x04, 0x84, 0x70, 0x61, 0x64, 0x03, 0x10, 0x00, 0x00, 0x00, 0x04, 0x84, 0x67, 0x61, 0x70, 0x03, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x8b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x04, 0x86, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x04, 0x87, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x04, 0x86, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x04, 0x85, 0x74, 0x65, 0x78, 0x74, 0x04, 0x86, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x04, 0x88, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x04, 0x86, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x84, 0x72, 0x6f, 0x77, 0x11, 0x03, 0x08, 0x00, 0x00, 0x00, 0x04, 0x88, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x79, 0x04, 0x84, 0x65, 0x6e, 0x64, 0x04, 0x87, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x01, 0x04, 0x87, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x04, 0x86, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x04, 0x89, 0x6f, 0x6e, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x04, 0x8a, 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x04, 0x83, 0x6f, 0x6b, 0x04, 0x86, 0x6f, 0x6e, 0x5f, 0x6f, 0x6b, 0x04, 0x84, 0x62, 0x6f, 0x78, 0x04, 0x83, 0x61, 0x74, 0x04, 0x82, 0x78, 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x82, 0x79, 0x04, 0x85, 0x66, 0x69, 0x6c, 0x6c, 0x04, 0x82, 0x68, 0x04, 0x88, 0x63, 0x61, 0x70, 0x74, 0x75, 0x72, 0x65, 0x04, 0x86, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x04, 0x87, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x04, 0x8b, 0x6f, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x73, 0x69, 0x64, 0x65, 0x81, 0x01, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xa3, 0x02, 0xa8, 0x00, 0x00, 0x02, 0x8a, 0x0b, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x01, 0x44, 0x00, 0x01, 0x01, 0x09, 0x00, 0x01, 0x00, 0x44, 0x00, 0x01, 0x01, 0x05, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x47, 0x00, 0x01, 0x00, 0x82, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x86, 0x72, 0x65, 0x73, 0x65, 0x74, 0x84, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x01, 0x08, 0x00, 0x01, 0x0a, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xae, 0x02, 0xbb, 0x01, 0x00, 0x05, 0x9f, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x93, 0x01, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0b, 0x02, 0x01, 0x03, 0x0e, 0x02, 0x04, 0x02, 0x92, 0x01, 0x02, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x0e, 0x02, 0x04, 0x04, 0x92, 0x01, 0x04, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x0e, 0x02, 0x04, 0x05, 0x92, 0x01, 0x05, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x0e, 0x02, 0x04, 0x06, 0x92, 0x01, 0x06, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x0e, 0x02, 0x04, 0x07, 0x92, 0x01, 0x07, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x0e, 0x02, 0x04, 0x08, 0x92, 0x01, 0x08, 0x04, 0x0b, 0x02, 0x01, 0x03, 0x0e, 0x02, 0x04, 0x09, 0x92, 0x01, 0x09, 0x04, 0x0b, 0x02, 0x00, 0x0b, 0x0e, 0x02, 0x04, 0x0c, 0x92, 0x01, 0x0a, 0x04, 0xc4, 0x00, 0x03, 0x01, 0xc7, 0x00, 0x01, 0x00, 0x8d, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x89, 0x73, 0x65, 0x74, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x04, 0x86, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x86, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x04, 0x8b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x04, 0x85, 0x66, 0x61, 0x63, 0x65, 0x04, 0x8c, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x46, 0x61, 0x63, 0x65, 0x04, 0x8d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x8b, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x04, 0x87, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x04, 0x85, 0x66, 0x6f, 0x6e, 0x74, 0x04, 0x84, 0x67, 0x75, 0x69, 0x04, 0x88, 0x46, 0x4f, 0x4e, 0x54, 0x5f, 0x55, 0x49, 0x82, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xc0, 0x02, 0xc8, 0x02, 0x00, 0x06, 0x9b, 0x0b, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x02, 0x01, 0x80, 0x01, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x83, 0x02, 0x01, 0x00, 0x44, 0x01, 0x04, 0x01, 0x09, 0x01, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x44, 0x01, 0x02, 0x01, 0xc2, 0x00, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x0b, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x02, 0x03, 0x80, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x44, 0x01, 0x03, 0x01, 0x0b, 0x01, 0x00, 0x04, 0x93, 0x01, 0x01, 0x00, 0x52, 0x00, 0x00, 0x00, 0x92, 0x01, 0x05, 0x00, 0x09, 0x02, 0x02, 0x00, 0x44, 0x01, 0x03, 0x02, 0x0a, 0x01, 0x03, 0x00, 0x94, 0x81, 0x02, 0x06, 0xc4, 0x01, 0x02, 0x01, 0x48, 0x01, 0x02, 0x00, 0xc7, 0x01, 0x01, 0x00, 0x87, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x88, 0x73, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x04, 0x85, 0x66, 0x69, 0x6c, 0x6c, 0x04, 0x89, 0x73, 0x65, 0x74, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x04, 0x8d, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x04, 0x85, 0x72, 0x6f, 0x6f, 0x74, 0x04, 0x89, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x84, 0x00, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x01, 0x15, 0x00, 0x01, 0x0a, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xca, 0x02, 0xd0, 0x01, 0x00, 0x07, 0x9d, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x00, 0x02, 0x81, 0x81, 0xff, 0x7f, 0x01, 0x82, 0xff, 0x7f, 0x8b, 0x02, 0x00, 0x03, 0x8e, 0x02, 0x05, 0x04, 0xc4, 0x02, 0x01, 0x02, 0x0b, 0x03, 0x00, 0x03, 0x0e, 0x03, 0x06, 0x05, 0x44, 0x03, 0x01, 0x00, 0xc4, 0x00, 0x00, 0x03, 0xc2, 0x80, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x80, 0x8b, 0x01, 0x00, 0x06, 0x00, 0x02, 0x02, 0x00, 0x81, 0x82, 0x00, 0x80, 0xc4, 0x01, 0x03, 0x01, 0x8b, 0x01, 0x00, 0x00, 0x8e, 0x01, 0x03, 0x07, 0xc4, 0x01, 0x01, 0x01, 0x87, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x01, 0x00, 0x8b, 0x01, 0x00, 0x03, 0x8e, 0x01, 0x03, 0x08, 0x0b, 0x02, 0x02, 0x09, 0x0e, 0x02, 0x04, 0x0a, 0xc4, 0x01, 0x02, 0x01, 0xc7, 0x01, 0x01, 0x00, 0x8b, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x87, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x04, 0x85, 0x72, 0x6f, 0x6f, 0x74, 0x04, 0x84, 0x67, 0x75, 0x69, 0x04, 0x89, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68, 0x04, 0x8a, 0x67, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x04, 0x86, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x04, 0x8c, 0x64, 0x72, 0x6f, 0x70, 0x53, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x04, 0x86, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x04, 0x86, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x04, 0x8b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x01, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xd2, 0x02, 0xd4, 0x01, 0x00, 0x03, 0x85, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x00, 0x02, 0xc4, 0x00, 0x02, 0x01, 0xc7, 0x00, 0x01, 0x00, 0x83, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x85, 0x64, 0x72, 0x61, 0x77, 0x04, 0x85, 0x72, 0x6f, 0x6f, 0x74, 0x81, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xd6, 0x02, 0xd9, 0x03, 0x00, 0x08, 0x94, 0x8b, 0x01, 0x00, 0x00, 0x8e, 0x01, 0x03, 0x01, 0x00, 0x02, 0x00, 0x00, 0xc4, 0x01, 0x02, 0x05, 0xbb, 0x01, 0x01, 0x00, 0xb8, 0x04, 0x00, 0x80, 0xa2, 0x03, 0x03, 0x05, 0xae, 0x01, 0x05, 0x06, 0xba, 0x00, 0x07, 0x00, 0xb8, 0x02, 0x00, 0x80, 0x3b, 0x02, 0x02, 0x00, 0xb8, 0x01, 0x00, 0x80, 0xa2, 0x03, 0x04, 0x06, 0x2e, 0x02, 0x06, 0x06, 0x3a, 0x81, 0x07, 0x00, 0x38, 0x00, 0x00, 0x80, 0x86, 0x03, 0x00, 0x00, 0x87, 0x03, 0x00, 0x00, 0xc8, 0x03, 0x02, 0x00, 0xc7, 0x03, 0x01, 0x00, 0x82, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x88, 0x67, 0x65, 0x74, 0x52, 0x65, 0x63, 0x74, 0x81, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xdb, 0x02, 0xdf, 0x03, 0x00, 0x08, 0x93, 0x89, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x03, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x8b, 0x01, 0x01, 0x00, 0x8e, 0x01, 0x03, 0x01, 0x00, 0x02, 0x00, 0x00, 0x87, 0x02, 0x00, 0x00, 0xc4, 0x01, 0x03, 0x01, 0x89, 0x01, 0x02, 0x00, 0x8c, 0x01, 0x03, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x00, 0x02, 0x03, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x80, 0x03, 0x02, 0x00, 0x44, 0x02, 0x04, 0x01, 0x47, 0x02, 0x01, 0x00, 0x82, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x8b, 0x73, 0x65, 0x74, 0x50, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x83, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xe1, 0x02, 0xe5, 0x03, 0x00, 0x08, 0x93, 0x89, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x03, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x8b, 0x01, 0x01, 0x00, 0x8e, 0x01, 0x03, 0x01, 0x00, 0x02, 0x00, 0x00, 0x85, 0x02, 0x00, 0x00, 0xc4, 0x01, 0x03, 0x01, 0x89, 0x01, 0x02, 0x00, 0x8c, 0x01, 0x03, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x00, 0x02, 0x03, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x80, 0x03, 0x02, 0x00, 0x44, 0x02, 0x04, 0x01, 0x47, 0x02, 0x01, 0x00, 0x82, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x8b, 0x73, 0x65, 0x74, 0x50, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x83, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xea, 0x02, 0xf7, 0x03, 0x00, 0x09, 0xa5, 0x8b, 0x01, 0x00, 0x00, 0x8e, 0x01, 0x03, 0x01, 0xc4, 0x01, 0x01, 0x02, 0xc2, 0x01, 0x00, 0x00, 0x38, 0x05, 0x00, 0x80, 0x0b, 0x02, 0x00, 0x00, 0x0e, 0x02, 0x04, 0x02, 0x88, 0x02, 0x00, 0x00, 0x44, 0x02, 0x02, 0x01, 0x09, 0x02, 0x01, 0x00, 0x0c, 0x02, 0x04, 0x03, 0x42, 0x02, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x80, 0x02, 0x04, 0x00, 0x00, 0x03, 0x03, 0x00, 0xc4, 0x02, 0x02, 0x01, 0x0b, 0x02, 0x00, 0x00, 0x0e, 0x02, 0x04, 0x03, 0x8e, 0x02, 0x00, 0x04, 0x00, 0x03, 0x01, 0x00, 0x80, 0x03, 0x02, 0x00, 0x44, 0x02, 0x04, 0x02, 0x42, 0x82, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x85, 0x02, 0x00, 0x00, 0xc8, 0x02, 0x02, 0x00, 0x80, 0x02, 0x04, 0x00, 0x12, 0x80, 0x06, 0x07, 0x12, 0x00, 0x05, 0x05, 0x89, 0x02, 0x02, 0x00, 0x00, 0x03, 0x04, 0x00, 0x80, 0x03, 0x01, 0x00, 0x00, 0x04, 0x02, 0x00, 0xc4, 0x02, 0x04, 0x01, 0x87, 0x02, 0x00, 0x00, 0xc8, 0x02, 0x02, 0x00, 0xc7, 0x02, 0x01, 0x00, 0x88, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x89, 0x67, 0x65, 0x74, 0x46, 0x6f, 0x63, 0x75, 0x73, 0x04, 0x89, 0x73, 0x65, 0x74, 0x46, 0x6f, 0x63, 0x75, 0x73, 0x04, 0x84, 0x68, 0x69, 0x74, 0x04, 0x85, 0x72, 0x6f, 0x6f, 0x74, 0x04, 0x89, 0x63, 0x61, 0x70, 0x74, 0x75, 0x72, 0x65, 0x64, 0x04, 0x87, 0x69, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x11, 0x83, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x01, 0x17, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0xfc, 0x03, 0x85, 0x03, 0x00, 0x09, 0x9e, 0x8e, 0x01, 0x00, 0x00, 0xc2, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x05, 0x02, 0x00, 0x00, 0x48, 0x02, 0x02, 0x00, 0x09, 0x02, 0x00, 0x00, 0x80, 0x02, 0x03, 0x00, 0x00, 0x03, 0x01, 0x00, 0x80, 0x03, 0x02, 0x00, 0x44, 0x02, 0x04, 0x02, 0x8e, 0x02, 0x00, 0x01, 0x39, 0x82, 0x05, 0x00, 0xb8, 0x06, 0x00, 0x80, 0x12, 0x00, 0x01, 0x04, 0x42, 0x02, 0x00, 0x00, 0xb8, 0x02, 0x00, 0x80, 0x89, 0x02, 0x01, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80, 0x03, 0x01, 0x00, 0x00, 0x04, 0x02, 0x00, 0xc4, 0x02, 0x04, 0x01, 0x38, 0x02, 0x00, 0x80, 0x89, 0x02, 0x02, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80, 0x03, 0x01, 0x00, 0x00, 0x04, 0x02, 0x00, 0xc4, 0x02, 0x04, 0x01, 0x87, 0x02, 0x00, 0x00, 0xc8, 0x02, 0x02, 0x00, 0xc7, 0x02, 0x01, 0x00, 0x82, 0x04, 0x89, 0x63, 0x61, 0x70, 0x74, 0x75, 0x72, 0x65, 0x64, 0x04, 0x87, 0x69, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x83, 0x01, 0x16, 0x00, 0x01, 0x17, 0x00, 0x01, 0x18, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x03, 0x8a, 0x03, 0x94, 0x03, 0x00, 0x0b, 0xa6, 0x8e, 0x01, 0x00, 0x00, 0xc2, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x05, 0x02, 0x00, 0x00, 0x48, 0x02, 0x02, 0x00, 0x0e, 0x02, 0x00, 0x01, 0x89, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80, 0x03, 0x01, 0x00, 0x00, 0x04, 0x02, 0x00, 0xc4, 0x02, 0x04, 0x02, 0xc2, 0x02, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x80, 0x09, 0x03, 0x01, 0x00, 0x0c, 0x03, 0x06, 0x03, 0x42, 0x83, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x08, 0x03, 0x00, 0x00, 0x88, 0x03, 0x00, 0x00, 0x12, 0x80, 0x01, 0x02, 0x12, 0x00, 0x00, 0x07, 0x42, 0x02, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x89, 0x03, 0x02, 0x00, 0x00, 0x04, 0x03, 0x00, 0x80, 0x04, 0x01, 0x00, 0x00, 0x05, 0x02, 0x00, 0xc4, 0x03, 0x04, 0x01, 0x42, 0x03, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x80, 0x03, 0x06, 0x00, 0x00, 0x04, 0x03, 0x00, 0x80, 0x04, 0x01, 0x00, 0x00, 0x05, 0x02, 0x00, 0xc4, 0x03, 0x04, 0x01, 0x87, 0x03, 0x00, 0x00, 0xc8, 0x03, 0x02, 0x00, 0xc7, 0x03, 0x01, 0x00, 0x83, 0x04, 0x89, 0x63, 0x61, 0x70, 0x74, 0x75, 0x72, 0x65, 0x64, 0x04, 0x87, 0x69, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x00, 0x83, 0x01, 0x16, 0x00, 0x01, 0x05, 0x00, 0x01, 0x18, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x03, 0x98, 0x03, 0x9f, 0x01, 0x00, 0x05, 0x8f, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x01, 0x01, 0x0e, 0x01, 0x00, 0x02, 0xc4, 0x00, 0x02, 0x02, 0xc2, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, 0x80, 0x09, 0x01, 0x01, 0x00, 0x0c, 0x01, 0x02, 0x01, 0x42, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x80, 0x01, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0xc4, 0x01, 0x02, 0x01, 0xc8, 0x00, 0x02, 0x00, 0x47, 0x01, 0x01, 0x00, 0x83, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x8b, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x46, 0x69, 0x72, 0x73, 0x74, 0x04, 0x85, 0x72, 0x6f, 0x6f, 0x74, 0x82, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x03, 0xa4, 0x03, 0xc8, 0x03, 0x00, 0x09, 0xde, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0xc4, 0x01, 0x02, 0x02, 0xbc, 0x81, 0x01, 0x00, 0xb8, 0x01, 0x00, 0x80, 0x8b, 0x01, 0x00, 0x02, 0x03, 0x82, 0x01, 0x00, 0x81, 0x82, 0x00, 0x80, 0xc4, 0x01, 0x03, 0x01, 0x89, 0x01, 0x01, 0x00, 0x8c, 0x01, 0x03, 0x01, 0xc2, 0x01, 0x00, 0x00, 0x38, 0x12, 0x00, 0x80, 0x42, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x87, 0x01, 0x00, 0x00, 0xc8, 0x01, 0x02, 0x00, 0x8b, 0x01, 0x00, 0x04, 0x8e, 0x01, 0x03, 0x05, 0xc4, 0x01, 0x01, 0x02, 0xc2, 0x81, 0x00, 0x00, 0x38, 0x02, 0x00, 0x80, 0x09, 0x02, 0x02, 0x00, 0x80, 0x02, 0x00, 0x00, 0x44, 0x02, 0x02, 0x01, 0x07, 0x02, 0x00, 0x00, 0x48, 0x02, 0x02, 0x00, 0x0b, 0x02, 0x00, 0x04, 0x0e, 0x02, 0x04, 0x06, 0x8e, 0x02, 0x00, 0x07, 0x00, 0x03, 0x01, 0x00, 0x44, 0x02, 0x03, 0x02, 0x39, 0x82, 0x03, 0x00, 0xb8, 0x06, 0x00, 0x80, 0x89, 0x02, 0x03, 0x00, 0x8c, 0x02, 0x05, 0x03, 0xc2, 0x02, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x00, 0x03, 0x05, 0x00, 0x80, 0x03, 0x03, 0x00, 0x44, 0x03, 0x02, 0x01, 0x09, 0x03, 0x04, 0x00, 0x0c, 0x03, 0x06, 0x04, 0x42, 0x03, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x80, 0x03, 0x06, 0x00, 0x00, 0x04, 0x04, 0x00, 0xc4, 0x03, 0x02, 0x01, 0x87, 0x02, 0x00, 0x00, 0xc8, 0x02, 0x02, 0x00, 0xbc, 0x80, 0x08, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x85, 0x01, 0x00, 0x00, 0xc8, 0x01, 0x02, 0x00, 0x8b, 0x01, 0x00, 0x04, 0x8e, 0x01, 0x03, 0x05, 0xc4, 0x01, 0x01, 0x02, 0xc2, 0x81, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x89, 0x01, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0xc4, 0x01, 0x02, 0x02, 0xc2, 0x81, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x80, 0x05, 0x02, 0x00, 0x00, 0x48, 0x02, 0x02, 0x00, 0x42, 0x01, 0x00, 0x00, 0x38, 0x03, 0x00, 0x80, 0x0b, 0x02, 0x00, 0x04, 0x0e, 0x02, 0x04, 0x09, 0x80, 0x02, 0x03, 0x00, 0x07, 0x03, 0x00, 0x00, 0x44, 0x02, 0x03, 0x01, 0x12, 0x00, 0x0a, 0x03, 0xb8, 0x07, 0x00, 0x80, 0x0e, 0x02, 0x00, 0x0a, 0x12, 0x80, 0x0a, 0x0b, 0x42, 0x02, 0x00, 0x00, 0xb8, 0x05, 0x00, 0x80, 0x8b, 0x02, 0x00, 0x04, 0x8e, 0x02, 0x05, 0x09, 0x00, 0x03, 0x04, 0x00, 0x85, 0x03, 0x00, 0x00, 0xc4, 0x02, 0x03, 0x01, 0x89, 0x02, 0x05, 0x00, 0x8c, 0x02, 0x05, 0x04, 0xc2, 0x02, 0x00, 0x00, 0x38, 0x01, 0x00, 0x80, 0x00, 0x03, 0x05, 0x00, 0x80, 0x03, 0x04, 0x00, 0x44, 0x03, 0x02, 0x01, 0x07, 0x02, 0x00, 0x00, 0x48, 0x02, 0x02, 0x00, 0x47, 0x02, 0x01, 0x00, 0x8c, 0x04, 0x85, 0x74, 0x79, 0x70, 0x65, 0x04, 0x88, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x04, 0x86, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x04, 0x9d, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x04, 0x85, 0x6e, 0x6f, 0x64, 0x65, 0x04, 0x89, 0x67, 0x65, 0x74, 0x46, 0x6f, 0x63, 0x75, 0x73, 0x04, 0x8a, 0x6d, 0x6f, 0x76, 0x65, 0x46, 0x6f, 0x63, 0x75, 0x73, 0x04, 0x85, 0x72, 0x6f, 0x6f, 0x74, 0x04, 0x88, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x04, 0x8b, 0x73, 0x65, 0x74, 0x50, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x04, 0x8b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x00, 0x86, 0x00, 0x00, 0x00, 0x01, 0x19, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x04, 0x00, 0x01, 0x03, 0x00, 0x01, 0x05, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; +const EmbeddedModule embedded_modules[] = { + {"hints", hints, sizeof(hints)}, + {"ui", ui, sizeof(ui)}, +}; +const size_t embedded_modules_count = 2; + + +} // namespace esp32lua diff --git a/native/src/runtime/loader.cpp b/native/src/runtime/loader.cpp index 3cbb43b..7a93eeb 100644 --- a/native/src/runtime/loader.cpp +++ b/native/src/runtime/loader.cpp @@ -2,6 +2,9 @@ // mount, so every path into the filesystem goes through FsProvider instead. #include +#include + +#include extern "C" { #include "lauxlib.h" @@ -82,6 +85,22 @@ int Runtime::searchModule(lua_State* state) { return 1; } +int Runtime::searchEmbedded(lua_State* state) { + const char* name = luaL_checkstring(state, 1); + for (size_t i = 0; i < embedded_modules_count; i++) { + if (std::strcmp(name, embedded_modules[i].name) != 0) continue; + const std::string chunkname = std::string("=") + name; + if (luaL_loadbuffer(state, reinterpret_cast(embedded_modules[i].data), + embedded_modules[i].size, chunkname.c_str()) != LUA_OK) { + return luaL_error(state, "error loading embedded module '%s': %s", name, lua_tostring(state, -1)); + } + lua_pushstring(state, name); + return 2; + } + lua_pushfstring(state, "\n\tno embedded module '%s'", name); + return 1; +} + int Runtime::loadFile(lua_State* state) { Runtime* runtime = Runtime::from(state); if (load(state, *runtime->providers_.fs, luaL_checkstring(state, 1)) == LUA_OK) return 1; @@ -102,10 +121,12 @@ void Runtime::installLoader(const std::string& appDir) { lua_getfield(state_, -1, "searchers"); lua_pushcfunction(state_, searchModule); lua_rawseti(state_, -2, 2); - for (int at = 3; at <= 4; at++) { - lua_pushnil(state_); - lua_rawseti(state_, -2, at); - } + // Embedded bytecode is the fallback after the SD card, so a local /.lua/lib/ui.lua shadows + // the packaged one without reflashing. + lua_pushcfunction(state_, searchEmbedded); + lua_rawseti(state_, -2, 3); + lua_pushnil(state_); + lua_rawseti(state_, -2, 4); lua_pop(state_, 2); lua_pushcfunction(state_, loadFile); diff --git a/tools/dump.c b/tools/dump.c new file mode 100644 index 0000000..e23a451 --- /dev/null +++ b/tools/dump.c @@ -0,0 +1,36 @@ +// Dumps a Lua source file as bytecode, linked against the same vendored Lua the firmware +// runs (LUA_32BITS), so the header matches. Stand-in for luac when only the library is +// vendored. + +#include +#include + +#include "lauxlib.h" +#include "lua.h" + +static int writer(lua_State*, const void* p, size_t size, void* ud) { + return fwrite(p, 1, size, (FILE*)ud) != size ? 1 : 0; +} + +int main(int argc, char** argv) { + if (argc != 3) { + fprintf(stderr, "usage: %s input.lua output.luac\n", argv[0]); + return 1; + } + lua_State* L = luaL_newstate(); + if (luaL_loadfilex(L, argv[1], "t") != LUA_OK) { + fprintf(stderr, "%s: %s\n", argv[1], lua_tostring(L, -1)); + lua_close(L); + return 1; + } + FILE* out = fopen(argv[2], "wb"); + if (!out) { + fprintf(stderr, "cannot open %s\n", argv[2]); + lua_close(L); + return 1; + } + const int err = lua_dump(L, writer, out, 1); // strip debug info + fclose(out); + lua_close(L); + return err ? 1 : 0; +} diff --git a/tools/embed.py b/tools/embed.py new file mode 100644 index 0000000..f7350ba --- /dev/null +++ b/tools/embed.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +"""Compiles lua/lib/*.lua to LUA_32BITS bytecode and generates a C++ source file embedding +the arrays. The runtime's module searcher checks these as a fallback after the SD card, so +a local copy always shadows the packaged one. + +Usage: + tools/embed.py [--check] +""" + +import subprocess +import sys +import pathlib + +HEADER = """\ +// GENERATED by tools/embed.py — do not edit. Run `make embed` to regenerate. +#include + +namespace esp32lua { + +""" + +FOOTER = """ + +} // namespace esp32lua +""" + + +def main(): + check = "--check" in sys.argv + args = [a for a in sys.argv[1:] if a != "--check"] + if len(args) != 3: + sys.exit("usage: embed.py [--check]") + + luac32, lib_dir, out_path = args + lib_dir = pathlib.Path(lib_dir) + out_path = pathlib.Path(out_path) + + sources = sorted(lib_dir.glob("*.lua")) + arrays = [] + rows = [] + for src in sources: + import tempfile + with tempfile.NamedTemporaryFile(suffix=".luac", delete=False) as tmp: + tmp_path = tmp.name + subprocess.run([luac32, str(src), tmp_path], check=True) + bytecode = pathlib.Path(tmp_path).read_bytes() + pathlib.Path(tmp_path).unlink() + name = src.stem + comma = ", ".join(f"0x{b:02x}" for b in bytecode) + arrays.append(f"static const unsigned char {name}[] = {{{comma}}};\n") + rows.append(f' {{"{name}", {name}, sizeof({name})}},') + + footer = "const EmbeddedModule embedded_modules[] = {{\n{rows}\n}};\nconst size_t embedded_modules_count = {count};\n" + generated = HEADER + "".join(arrays) + footer.format(rows="\n".join(rows), count=len(sources)) + FOOTER + + if check: + existing = out_path.read_text() if out_path.exists() else "" + if existing != generated: + sys.exit(f"{out_path} is stale; run `make embed`") + return + + out_path.write_text(generated) + print(f"wrote {len(sources)} modules to {out_path}") + + +if __name__ == "__main__": + main()