From b48c8407aa97329e54694215f5266f3b53358eae Mon Sep 17 00:00:00 2001 From: JamesonHuang <462430725@qq.com> Date: Mon, 11 May 2015 11:05:24 +0800 Subject: [PATCH] add h10 code --- Me_Lua/h10/MZLog.lua | 14 + Me_Lua/h10/Posix.lua | 113 ++ Me_Lua/h10/cjson.so | Bin 0 -> 30666 bytes Me_Lua/h10/lfs.so | Bin 0 -> 16916 bytes Me_Lua/h10/lsqlite3.so | Bin 0 -> 40103 bytes Me_Lua/h10/ltn12.lua | 305 +++ Me_Lua/h10/luci/controller/admin/network.lua | 610 ++++++ Me_Lua/h10/luci/controller/api/index.lua | 308 +++ Me_Lua/h10/luci/controller/bs/index.lua | 149 ++ Me_Lua/h10/luci/dispatcher.lua | 965 ++++++++++ Me_Lua/h10/luci/model/network.lua | 1632 ++++++++++++++++ Me_Lua/h10/luci/sauth.lua | 200 ++ Me_Lua/h10/meizu/arpmon.lua | 99 + Me_Lua/h10/meizu/bfs.lua | 511 +++++ Me_Lua/h10/meizu/btfs.lua | 1442 +++++++++++++++ Me_Lua/h10/meizu/dbfs.lua | 604 ++++++ Me_Lua/h10/meizu/disk.lua | 63 + Me_Lua/h10/meizu/dlfs.lua | 670 +++++++ Me_Lua/h10/meizu/nwfs.lua | 1747 ++++++++++++++++++ Me_Lua/h10/meizu/r10config.lua | 3 + Me_Lua/h10/meizu/sipfs.lua | 906 +++++++++ Me_Lua/h10/meizu/upgdfs.lua | 256 +++ Me_Lua/h10/mime.lua | 90 + Me_Lua/h10/mime.so.1.0.3 | Bin 0 -> 84630 bytes Me_Lua/h10/mime/core.so | Bin 0 -> 84630 bytes Me_Lua/h10/posix.so | Bin 0 -> 34716 bytes Me_Lua/h10/routerReport.lua | 144 ++ Me_Lua/h10/socket.lua | 149 ++ Me_Lua/h10/socket.so.3.0-rc1 | Bin 0 -> 289771 bytes Me_Lua/h10/socket/core.so | Bin 0 -> 289771 bytes Me_Lua/h10/socket/ftp.lua | 285 +++ Me_Lua/h10/socket/headers.lua | 104 ++ Me_Lua/h10/socket/http.lua | 356 ++++ Me_Lua/h10/socket/smtp.lua | 256 +++ Me_Lua/h10/socket/tp.lua | 126 ++ Me_Lua/h10/socket/url.lua | 307 +++ Me_Lua/h10/ssl.lua | 168 ++ Me_Lua/h10/ssl.so | Bin 0 -> 53826 bytes Me_Lua/h10/ssl/https.lua | 138 ++ 39 files changed, 12720 insertions(+) create mode 100644 Me_Lua/h10/MZLog.lua create mode 100644 Me_Lua/h10/Posix.lua create mode 100644 Me_Lua/h10/cjson.so create mode 100755 Me_Lua/h10/lfs.so create mode 100644 Me_Lua/h10/lsqlite3.so create mode 100644 Me_Lua/h10/ltn12.lua create mode 100644 Me_Lua/h10/luci/controller/admin/network.lua create mode 100644 Me_Lua/h10/luci/controller/api/index.lua create mode 100644 Me_Lua/h10/luci/controller/bs/index.lua create mode 100644 Me_Lua/h10/luci/dispatcher.lua create mode 100644 Me_Lua/h10/luci/model/network.lua create mode 100644 Me_Lua/h10/luci/sauth.lua create mode 100644 Me_Lua/h10/meizu/arpmon.lua create mode 100644 Me_Lua/h10/meizu/bfs.lua create mode 100644 Me_Lua/h10/meizu/btfs.lua create mode 100644 Me_Lua/h10/meizu/dbfs.lua create mode 100644 Me_Lua/h10/meizu/disk.lua create mode 100644 Me_Lua/h10/meizu/dlfs.lua create mode 100644 Me_Lua/h10/meizu/nwfs.lua create mode 100644 Me_Lua/h10/meizu/r10config.lua create mode 100644 Me_Lua/h10/meizu/sipfs.lua create mode 100644 Me_Lua/h10/meizu/upgdfs.lua create mode 100644 Me_Lua/h10/mime.lua create mode 100644 Me_Lua/h10/mime.so.1.0.3 create mode 100644 Me_Lua/h10/mime/core.so create mode 100644 Me_Lua/h10/posix.so create mode 100644 Me_Lua/h10/routerReport.lua create mode 100644 Me_Lua/h10/socket.lua create mode 100644 Me_Lua/h10/socket.so.3.0-rc1 create mode 100644 Me_Lua/h10/socket/core.so create mode 100644 Me_Lua/h10/socket/ftp.lua create mode 100644 Me_Lua/h10/socket/headers.lua create mode 100644 Me_Lua/h10/socket/http.lua create mode 100644 Me_Lua/h10/socket/smtp.lua create mode 100644 Me_Lua/h10/socket/tp.lua create mode 100644 Me_Lua/h10/socket/url.lua create mode 100644 Me_Lua/h10/ssl.lua create mode 100644 Me_Lua/h10/ssl.so create mode 100644 Me_Lua/h10/ssl/https.lua diff --git a/Me_Lua/h10/MZLog.lua b/Me_Lua/h10/MZLog.lua new file mode 100644 index 0000000..c4a1177 --- /dev/null +++ b/Me_Lua/h10/MZLog.lua @@ -0,0 +1,14 @@ +module ("MZLog", package.seeall) + +function log(...) + local posix = require("posix") + local util = require("luci.util") + local priority = arg[1] + if priority and tonumber(priority) then + posix.openlog("luci", "nep", LOG_USER) + for i = 2, arg.n do + posix.syslog(priority, util.serialize_data(arg[i])) + end + posix.closelog() + end +end diff --git a/Me_Lua/h10/Posix.lua b/Me_Lua/h10/Posix.lua new file mode 100644 index 0000000..7536a2a --- /dev/null +++ b/Me_Lua/h10/Posix.lua @@ -0,0 +1,113 @@ +local base = _G +local string = require("string") +local M = require "posix" + +function M.timeradd (x,y) + local sec, usec = 0, 0 + if x.sec then sec = sec + x.sec end + if y.sec then sec = sec + y.sec end + if x.usec then usec = usec + x.usec end + if y.usec then usec = usec + y.usec end + if usec > 1000000 then + sec = sec + 1 + usec = usec - 1000000 + end + + return { sec = sec, usec = usec } +end + + +function M.timercmp (x, y) + local x = { sec = x.sec or 0, usec = x.usec or 0 } + local y = { sec = y.sec or 0, usec = y.usec or 0 } + if x.sec ~= y.sec then + return x.sec - y.sec + else + return x.usec - y.usec + end +end + + +function M.timersub (x,y) + local sec, usec = 0, 0 + if x.sec then sec = x.sec end + if y.sec then sec = sec - y.sec end + if x.usec then usec = x.usec end + if y.usec then usec = usec - y.usec end + if usec < 0 then + sec = sec - 1 + usec = usec + 1000000 + end + + return { sec = sec, usec = usec } +end + +function M.timesleep (x) + local sec, nsec = 0, 0 + y = M.gettimeofday(); + if( M.timercmp(x, y) > 0 ) then + sec = x.sec - y.sec + nsec = (x.usec - y.usec) * 1000 + if nsec < 0 then + sec = sec - 1 + nsec = nsec + 1000000000 + end + M.nanosleep(sec, nsec) + end +end + +function M.strsplit(str, delim, maxNb) + -- Eliminate bad cases... + if string.find(str, delim) == nil then + return { str } + end + if maxNb == nil or maxNb < 1 then + maxNb = 0 -- No limit + end + local result = {} + local pat = "(.-)" .. delim .. "()" + local nb = 0 + local lastPos + for part, pos in string.gfind(str, pat) do + nb = nb + 1 + result[nb] = part + lastPos = pos + if nb == maxNb then break end + end + -- Handle the last field + if nb ~= maxNb then + result[nb + 1] = string.sub(str, lastPos) + end + return result +end + +function M.var_dump(data, max_level, prefix) + if type(prefix) ~= "string" then + prefix = "" + end + if type(data) ~= "table" then + print(prefix .. tostring(data)) + else + print(data) + if max_level ~= 0 then + local prefix_next = prefix .. " " + print(prefix .. "{") + for k,v in pairs(data) do + io.stdout:write(prefix_next .. k .. " = ") + if type(v) ~= "table" or (type(max_level) == "number" and max_level <= 1) then + print(v) + else + if max_level == nil then + M.var_dump(v, nil, prefix_next) + else + M.var_dump(v, max_level - 1, prefix_next) + end + end + end + print(prefix .. "}") + end + end +end + + +return M diff --git a/Me_Lua/h10/cjson.so b/Me_Lua/h10/cjson.so new file mode 100644 index 0000000000000000000000000000000000000000..cec1fb6196a88775ecc98f8d12de269d0f379d7e GIT binary patch literal 30666 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 literal 0 HcmV?d00001 diff --git a/Me_Lua/h10/lfs.so b/Me_Lua/h10/lfs.so new file mode 100755 index 0000000000000000000000000000000000000000..1bc10dfa9282ab6049919f9aa6ad534b5c6f16af GIT binary patch literal 16916 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 UF`JpJd#>to)E*fFY23d2Z)8J*ZU6uP literal 0 HcmV?d00001 diff --git a/Me_Lua/h10/lsqlite3.so b/Me_Lua/h10/lsqlite3.so new file mode 100644 index 0000000000000000000000000000000000000000..8b8db6e065d137b430e5c17fb1ff7998400ea194 GIT binary patch literal 40103 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 h< +Copyright 2011 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +]]-- + +module("luci.controller.admin.network", package.seeall) + +function index() + local uci = require("luci.model.uci").cursor() + local page + + page = node("admin", "network") + page.target = firstchild() + page.title = _("Network") + page.order = 50 + page.index = true + +-- if page.inreq then + local has_switch = false + + uci:foreach("network", "switch", + function(s) + has_switch = true + return false + end) + + if has_switch then + page = node("admin", "network", "vlan") + page.target = cbi("admin_network/vlan") + page.title = _("Switch") + page.order = 20 + + page = entry({"admin", "network", "switch_status"}, call("switch_status"), nil) + page.leaf = true + end + + + local has_wifi = false + + uci:foreach("wireless", "wifi-device", + function(s) + has_wifi = true + return false + end) + + if has_wifi then + page = entry({"admin", "network", "wireless_join"}, call("wifi_join"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_add"}, call("wifi_add"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_delete"}, call("wifi_delete"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_status"}, call("wifi_status"), nil) + page.leaf = true + + page = entry({"admin", "network", "getWifiSettings"}, call("getWifiSettings"), nil) + page.leaf = true + + page = entry({"admin", "network", "getConnectInfo"}, call("lease_status"), nil) + page.leaf = true + + page = entry({"admin", "network", "getUpLoadSpeed"}, call("getUpLoadSpeed"), nil) + page.leaf = true + page = entry({"admin", "network", "getWanInfo"}, call("getWanInfo"), nil) + page.leaf = true + page = entry({"admin", "network", "getLanDhcp"}, call("getLanDhcp"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_reconnect"}, call("wifi_reconnect"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_shutdown"}, call("wifi_shutdown"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless"}, arcombine(template("admin_network/wifi_overview"), cbi("admin_network/wifi")), _("Wifi"), 15) + page.leaf = true + page.subindex = true + + if page.inreq then + local wdev + local net = require "luci.model.network".init(uci) + for _, wdev in ipairs(net:get_wifidevs()) do + local wnet + for _, wnet in ipairs(wdev:get_wifinets()) do + entry( + {"admin", "network", "wireless", wnet:id()}, + alias("admin", "network", "wireless"), + wdev:name() .. ": " .. wnet:shortname() + ) + end + end + end + end + + + page = entry({"admin", "network", "iface_add"}, cbi("admin_network/iface_add"), nil) + page.leaf = true + + page = entry({"admin", "network", "iface_delete"}, call("iface_delete"), nil) + page.leaf = true + + page = entry({"admin", "network", "iface_status"}, call("iface_status"), nil) + page.leaf = true + + page = entry({"admin", "network", "iface_reconnect"}, call("iface_reconnect"), nil) + page.leaf = true + + page = entry({"admin", "network", "iface_shutdown"}, call("iface_shutdown"), nil) + page.leaf = true + + page = entry({"admin", "network", "network"}, arcombine(cbi("admin_network/network"), cbi("admin_network/ifaces")), _("Interfaces"), 10) + page.leaf = true + page.subindex = true + + if page.inreq then + uci:foreach("network", "interface", + function (section) + local ifc = section[".name"] + if ifc ~= "loopback" then + entry({"admin", "network", "network", ifc}, + true, ifc:upper()) + end + end) + end + + + if nixio.fs.access("/etc/config/dhcp") then + page = node("admin", "network", "dhcp") + page.target = cbi("admin_network/dhcp") + page.title = _("DHCP and DNS") + page.order = 30 + + page = entry({"admin", "network", "dhcplease_status"}, call("lease_status"), nil) + page.leaf = true + + page = node("admin", "network", "hosts") + page.target = cbi("admin_network/hosts") + page.title = _("Hostnames") + page.order = 40 + end + + page = node("admin", "network", "routes") + page.target = cbi("admin_network/routes") + page.title = _("Static Routes") + page.order = 50 + + page = node("admin", "network", "diagnostics") + page.target = template("admin_network/diagnostics") + page.title = _("Diagnostics") + page.order = 60 + + page = entry({"admin", "network", "diag_ping"}, call("diag_ping"), nil) + page.leaf = true + + page = entry({"admin", "network", "diag_nslookup"}, call("diag_nslookup"), nil) + page.leaf = true + + page = entry({"admin", "network", "diag_traceroute"}, call("diag_traceroute"), nil) + page.leaf = true + + page = entry({"admin", "network", "diag_ping6"}, call("diag_ping6"), nil) + page.leaf = true + + page = entry({"admin", "network", "diag_traceroute6"}, call("diag_traceroute6"), nil) + page.leaf = true +end + +function wifi_join() + local function param(x) + return luci.http.formvalue(x) + end + + local function ptable(x) + x = param(x) + return x and (type(x) ~= "table" and { x } or x) or {} + end + + local dev = param("device") + local ssid = param("join") + + if dev and ssid then + local cancel = (param("cancel") or param("cbi.cancel")) and true or false + + if cancel then + luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless_join?device=" .. dev)) + else + local cbi = require "luci.cbi" + local tpl = require "luci.template" + local map = luci.cbi.load("admin_network/wifi_add")[1] + + if map:parse() ~= cbi.FORM_DONE then + tpl.render("header") + map:render() + tpl.render("footer") + end + end + else + luci.template.render("admin_network/wifi_join") + end +end + +function wifi_add() + local dev = luci.http.formvalue("device") + local ntm = require "luci.model.network".init() + + dev = dev and ntm:get_wifidev(dev) + + if dev then + local net = dev:add_wifinet({ + mode = "ap", + ssid = "OpenWrt", + encryption = "none" + }) + + ntm:save("wireless") + luci.http.redirect(net:adminlink()) + end +end + +function wifi_delete(network) + local ntm = require "luci.model.network".init() + local wnet = ntm:get_wifinet(network) + if wnet then + local dev = wnet:get_device() + local nets = wnet:get_networks() + if dev then + ntm:del_wifinet(network) + ntm:commit("wireless") + local _, net + for _, net in ipairs(nets) do + if net:is_empty() then + ntm:del_network(net:name()) + ntm:commit("network") + end + end + luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>/dev/null") + luci.sys.call("env -i /sbin/wifi reload >/dev/null 2>/dev/null") + end + end + + luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless")) +end + +function iface_status(ifaces) + local netm = require "luci.model.network".init() + local rv = { } + + local iface + for iface in ifaces:gmatch("[%w%.%-_]+") do + local net = netm:get_network(iface) + local device = net and net:get_interface() + if device then + local data = { + id = iface, + proto = net:proto(), + uptime = net:uptime(), + gwaddr = net:gwaddr(), + dnsaddrs = net:dnsaddrs(), + name = device:shortname(), + type = device:type(), + ifname = device:name(), + macaddr = device:mac(), + is_up = device:is_up(), + rx_bytes = device:rx_bytes(), + tx_bytes = device:tx_bytes(), + rx_packets = device:rx_packets(), + tx_packets = device:tx_packets(), + + ipaddrs = { }, + ip6addrs = { }, + subdevices = { } + } + + local _, a + for _, a in ipairs(device:ipaddrs()) do + data.ipaddrs[#data.ipaddrs+1] = { + addr = a:host():string(), + netmask = a:mask():string(), + prefix = a:prefix() + } + end + for _, a in ipairs(device:ip6addrs()) do + if not a:is6linklocal() then + data.ip6addrs[#data.ip6addrs+1] = { + addr = a:host():string(), + netmask = a:mask():string(), + prefix = a:prefix() + } + end + end + + for _, device in ipairs(net:get_interfaces() or {}) do + data.subdevices[#data.subdevices+1] = { + name = device:shortname(), + type = device:type(), + ifname = device:name(), + macaddr = device:mac(), + macaddr = device:mac(), + is_up = device:is_up(), + rx_bytes = device:rx_bytes(), + tx_bytes = device:tx_bytes(), + rx_packets = device:rx_packets(), + tx_packets = device:tx_packets(), + } + end + + rv[#rv+1] = data + else + rv[#rv+1] = { + id = iface, + name = iface, + type = "ethernet" + } + end + end + + if #rv > 0 then + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + return + end + + luci.http.status(404, "No such device") +end + +function iface_reconnect(iface) + local netmd = require "luci.model.network".init() + local net = netmd:get_network(iface) + if net then + luci.sys.call("env -i /sbin/ifup %q >/dev/null 2>/dev/null" % iface) + luci.http.status(200, "Reconnected") + return + end + + luci.http.status(404, "No such interface") +end + +function iface_shutdown(iface) + local netmd = require "luci.model.network".init() + local net = netmd:get_network(iface) + if net then + luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface) + luci.http.status(200, "Shutdown") + return + end + + luci.http.status(404, "No such interface") +end + +function iface_delete(iface) + local netmd = require "luci.model.network".init() + local net = netmd:del_network(iface) + if net then + luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface) + luci.http.redirect(luci.dispatcher.build_url("admin/network/network")) + netmd:commit("network") + netmd:commit("wireless") + return + end + + luci.http.status(404, "No such interface") +end + +function wifi_status(devs) + local s = require "luci.tools.status" + local rv = { } + + local dev + for dev in devs:gmatch("[%w%.%-]+") do + rv[#rv+1] = s.wifi_network(dev) + end + + if #rv > 0 then + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + return + end + + luci.http.status(404, "No such device") +end + +local function wifi_reconnect_shutdown(shutdown, wnet) + local netmd = require "luci.model.network".init() + local net = netmd:get_wifinet(wnet) + local dev = net:get_device() + if dev and net then + dev:set("disabled", nil) + net:set("disabled", shutdown and 1 or nil) + netmd:commit("wireless") + + luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>/dev/null") + + luci.sys.call("env -i /sbin/wifi reload >/dev/null 2>/dev/null") + + luci.http.status(200, shutdown and "Shutdown" or "Reconnected") + + return + end + + luci.http.status(404, "No such radio") +end + +function wifi_reconnect(wnet) + wifi_reconnect_shutdown(false, wnet) +end + +function wifi_shutdown(wnet) + wifi_reconnect_shutdown(true, wnet) +end + +function wifiNetworks() + local result = {} + local network = require "luci.model.network".init() + local dev + for _, dev in ipairs(network:get_wifidevs()) do + local rd = { + up = dev:is_up(), + device = dev:name(), + name = dev:get_i18n(), + networks = {} + } + local wifiNet + for _, wifiNet in ipairs(dev:get_wifinets()) do + rd.networks[#rd.networks+1] = { + name = wifiNet:shortname(), + up = wifiNet:is_up(), + mode = wifiNet:active_mode(), + ssid = wifiNet:active_ssid(), + bssid = wifiNet:active_bssid(), + encryption = wifiNet:active_encryption(), + frequency = wifiNet:frequency(), + channel = wifiNet:channel(), + signal = wifiNet:signal(), + quality = wifiNet:signal_percent(), + noise = wifiNet:noise(), + bitrate = wifiNet:bitrate(), + ifname = wifiNet:ifname(), + assoclist = wifiNet:assoclist(), + country = wifiNet:country(), + txpower = wifiNet:txpower(), + txpoweroff = wifiNet:txpower_offset(), + key = wifiNet:get("key"), + key1 = wifiNet:get("key1"), + encryption_src = wifiNet:get("encryption"), + hidden = wifiNet:get("hidden"), + } + end + result[#result+1] = rd + end + return result +end + +function wifiNetwork(wifiDeviceName) + local network = require "luci.model.network".init() + local wifiNet = network:get_wifinet(wifiDeviceName) + if wifiNet then + local dev = wifiNet:get_device() + if dev then + return { + id = wifiDeviceName, + name = wifiNet:shortname(), + up = wifiNet:is_up(), + mode = wifiNet:active_mode(), + ssid = wifiNet:active_ssid(), + bssid = wifiNet:active_bssid(), + encryption = wifiNet:active_encryption(), + encryption_src = wifiNet:get("encryption"), + frequency = wifiNet:frequency(), + channel = wifiNet:channel(), + signal = wifiNet:signal(), + quality = wifiNet:signal_percent(), + noise = wifiNet:noise(), + bitrate = wifiNet:bitrate(), + ifname = wifiNet:ifname(), + assoclist = wifiNet:assoclist(), + country = wifiNet:country(), + txpower = wifiNet:txpower(), + txpoweroff = wifiNet:txpower_offset(), + key = wifiNet:get("key"), + key1 = wifiNet:get("key1"), + hidden = wifiNet:get("hidden"), + device = { + up = dev:is_up(), + device = dev:name(), + name = dev:get_i18n() + } + } + end + end + return {} +end + +function getWifiSettings() + local infoList = {} + local wifis = wifiNetworks() + for i,wifiNet in ipairs(wifis) do + local item = {} + local index = 1 + if wifiNet["up"] then + item["status"] = "1" + else + item["status"] = "0" + end + local encryption = wifiNet.networks[index].encryption_src + local key = wifiNet.networks[index].key + if encryption == "wep-open" then + key = wifiNet.networks[index].key1 + if key:len()>4 and key:sub(0,2)=="s:" then + key = key:sub(3) + end + end + local channel = wifiNet.networks[index].cchannel + -- local channelparseinfo = channelHelper(channel) + item["ifname"] = wifiNet.networks[index].ifname + item["device"] = wifiNet.device..".network"..index + item["ssid"] = wifiNet.networks[index].ssid + -- item["channel"] = channelparseinfo.channel + -- item["channelInfo"] = getBandList(channel) + -- item["channelInfo"]["channel"] = wifiNet.networks[index].channel + item["mode"] = wifiNet.networks[index].mode + item["hidden"] = wifiNet.networks[index].hidden or 0 + item["signal"] = wifiNet.networks[index].signal + item["password"] = key + item["encryption"] = encryption + infoList[#wifis+1-i] = item + end + --local guestwifi = getGuestWifi(1) + -- if guestwifi then + -- table.insert(infoList, guestwifi) + -- end + --return infoList + local result = {} + -- local code = 0 + -- result["info"] = infoList + -- result["code"] = code + luci.http.write_json(infoList) +end + +function lease_status() + local s = require "luci.tools.status" + + luci.http.prepare_content("application/json") + luci.http.write('[') + luci.http.write_json(s.dhcp_leases()) + luci.http.write(',') + luci.http.write_json(s.dhcp6_leases()) + luci.http.write(']') +end + +function switch_status(switches) + local s = require "luci.tools.status" + + luci.http.prepare_content("application/json") + luci.http.write_json(s.switch_status(switches)) +end + +function diag_command(cmd, addr) + if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then + luci.http.prepare_content("text/plain") + + local util = io.popen(cmd % addr) + if util then + while true do + local ln = util:read("*l") + if not ln then break end + luci.http.write(ln) + luci.http.write("\n") + end + + util:close() + end + + return + end + + luci.http.status(500, "Bad address") +end + +function diag_ping(addr) + diag_command("ping -c 5 -W 1 %q 2>&1", addr) +end + +function diag_traceroute(addr) + diag_command("traceroute -q 1 -w 1 -n %q 2>&1", addr) +end + +function diag_nslookup(addr) + diag_command("nslookup %q 2>&1", addr) +end + +function diag_ping6(addr) + diag_command("ping6 -c 5 %q 2>&1", addr) +end + +function diag_traceroute6(addr) + diag_command("traceroute6 -q 1 -w 2 -n %q 2>&1", addr) +end + diff --git a/Me_Lua/h10/luci/controller/api/index.lua b/Me_Lua/h10/luci/controller/api/index.lua new file mode 100644 index 0000000..37a0689 --- /dev/null +++ b/Me_Lua/h10/luci/controller/api/index.lua @@ -0,0 +1,308 @@ +module("luci.controller.api.index", package.seeall) + +local bfs = require "meizu.bfs" +local cjson = require "cjson" +local disk = require "meizu.disk" +local dlfs = require "meizu.dlfs" +local lfs = require "lfs" +local lue = require("luci.util").exec +local nwfs = require "meizu.nwfs" +local RC = require "meizu.r10config" +local sipfs = require "meizu.sipfs" +local upgdfs = require "meizu.upgdfs" +local btfs = require "meizu.btfs" + +b64dec = bfs.b64dec +batchfile_checklist = bfs.batchfile_checklist +batchfile_compare_upload = bfs.batchfile_compare_upload +bind_router = bfs.bind_router +data_to_json = bfs.data_to_json +exec_cmd_in_sh = bfs.exec_cmd_in_sh +exec_reboot = bfs.exec_reboot +findInDir = bfs.findInDir +get_device_SN = bfs.get_device_SN +get_device_version = bfs.get_device_version +get_https_data = bfs.get_https_data +getFilesList = bfs.getFilesList +factory_reset = bfs.factory_reset +rts_get_access_token = bfs.rts_get_access_token +set_passwd = bfs.set_passwd +silent_upgrade = bfs.silent_upgrade + +nw_get_disk_info = disk.nw_get_disk_info +disk_formatting = disk.disk_formatting + +sip = sipfs.sip +pysip = sipfs.pysip +upload_router_log = sipfs.upload_router_log + +nw_check_sys_password = nwfs.nw_check_sys_password +nw_get_connect_device_list = nwfs.nw_get_connect_device_list +nw_get_device_details = nwfs.nw_get_device_details +nw_get_wan_type = nwfs.nw_get_wan_type +nw_get_smbswitch = nwfs.nw_get_smbswitch +nw_get_wifi_settings = nwfs.nw_get_wifi_settings +nw_set_device_name = nwfs.nw_set_device_name +nw_set_disk_access = nwfs.nw_set_disk_access +nw_set_wan_switch = nwfs.nw_set_wan_switch +nw_set_wan_type = nwfs.nw_set_wan_type +nw_set_smbswitch = nwfs.nw_set_smbswitch +nw_wifi_settings = nwfs.nw_wifi_settings +nw_get_tx_power_mode = nwfs.nw_get_tx_power_mode +nw_set_tx_power_mode = nwfs.nw_set_tx_power_mode +nw_get_wireless_channel = nwfs.nw_get_wireless_channel +nw_set_wireless_channel = nwfs.nw_set_wireless_channel + +get_connect_info = nwfs.get_connect_info +get_net_device = nwfs.get_net_device +real_time_net_speed = nwfs.real_time_net_speed + +nw_scan_ble_switch = btfs.nw_scan_ble_switch +nw_get_ble_device_list = btfs.nw_get_ble_device_list +nw_add_ble_mesh_device = btfs.nw_add_ble_mesh_device +nw_get_ble_device_status = btfs.nw_get_ble_device_status +nw_get_mesh_device_list = btfs.nw_get_mesh_device_list +nw_remove_ble_from_mesh = btfs.nw_remove_ble_from_mesh +nw_dismiss_mesh = btfs.nw_dismiss_mesh +nw_set_mesh_device_attr = btfs.nw_set_mesh_device_attr +nw_reboot_mesh_device = btfs.nw_reboot_mesh_device +nw_unmesh_all_device = btfs.nw_unmesh_all_device +nw_set_mesh_device_timer = btfs.nw_set_mesh_device_timer +nw_del_mesh_device_timer = btfs.nw_del_mesh_device_timer +nw_set_mesh_network_pwd = btfs.nw_set_mesh_network_pwd +nw_set_lamp_brightness = btfs.nw_set_lamp_brightness + +check_upgrade = upgdfs.check_upgrade +do_upgrade = upgdfs.do_upgrade +local_upgrade = upgdfs.local_upgrade + +nw_download_task_operate = dlfs.nw_download_task_operate +nw_get_active_list = dlfs.nw_get_active_list +nw_get_history_list = dlfs.nw_get_history_list +--nw_get_pause_list = dlfs.nw_get_pause_list +nw_thunder_get_bind_code = dlfs.nw_thunder_get_bind_code + +nw_download_task_start = dlfs.nw_download_task_start + +function index() + --nw: abridged for "Nei Wang"; ww abridged for "Wai Wang" + local root = node() + if not root.target then + root.target = alias("api") + root.index = true + end + local page = node("api") + page.target = firstchild() + page.title = _("api") + page.order = 10 + page.index = true + page.sysauth = "root" + page.sysauth_authenticator = "htmlauth" + --page = entry({"api", "getUserAccessToken"}, call("get_user_access_token"), nil, nil) + --page.leaf = true + page = entry({"api", "bindRouter"}, call("bind_router"), nil, nil) + page.leaf = true + --page = entry({"api", "unbindRouter"}, call("unbind_router"), nil, nil) + --page.leaf = true + --page = entry({"api", "getDeviceAccessToken"}, call("rts_get_access_token"), nil, nil) + --page.leaf = true + + page = entry({"api", "sip"}, call("sip"), nil, nil) + page.leaf = true + page = entry({"api", "pysip"}, call("pysip"), nil, nil) + page.leaf = true + + page = entry({"api", "getconnectinfo"}, call("get_connect_info"), nil) + page.leaf = true + page = entry({"api", "getWifiSettings"}, call("nw_get_wifi_settings"), nil) + page.leaf = true + page = entry({"api", "getConnectDeviceList"}, call("nw_get_connect_device_list"), nil) + page.leaf = true + page = entry({"api", "getdevicedetails"}, call("nw_get_device_details"), nil) + page.leaf = true + page = entry({"api", "getNetDevice"}, call("get_net_device"), nil) + page.leaf = true + page = entry({"api", "getWanType"}, call("nw_get_wan_type"), nil) + page.leaf = true + page = entry({"api", "realtimenetspeed"}, call("nw_real_time_net_speed"), nil, nil) + page.leaf = true + page = entry({"api", "setWanType"}, call("nw_set_wan_type"), nil) + page.leaf = true + page = entry({"api", "setDeviceName"}, call("nw_set_device_name"), nil) + page.leaf = true + page = entry({"api", "setDiskAccess"}, call("nw_set_disk_access"), nil) + page.leaf = true + page = entry({"api", "setWanSwitch"}, call("nw_set_wan_switch"), nil) + page.leaf = true + page = entry({"api", "wifiSettings"}, call("nw_wifi_settings"), nil) + page.leaf = true + page = entry({"api", "gettxpowermode"}, call("nw_get_tx_power_mode"), nil) + page.leaf = true + page = entry({"api", "settxpowermode"}, call("nw_set_tx_power_mode"), nil) + page.leaf = true + page = entry({"api", "getWirelessChannel"}, call("nw_get_wireless_channel"), nil) + page.leaf = true + page = entry({"api", "setWirelessChannel"}, call("nw_set_wireless_channel"), nil) + page.leaf = true + + page = entry({"api", "diskinfo"}, call("nw_get_disk_info"), nil) + page.leaf = true + page = entry({"api", "diskformat"}, call("disk_formatting"), nil, nil) + page.leaf = true + + page = entry({"api", "factoryreset"}, call("factory_reset"), nil, nil) + page.leaf = true + page = entry({"api", "reboot"}, call("nw_exec_reboot"), nil, nil) + page.leaf = true + page = entry({"api", "localupgrade"}, call("local_upgrade"), nil, nil) + page.leaf = true + page = entry({"api", "silentupgrade"}, call("silent_upgrade"), nil, nil) + page.leaf = true + + page = entry({"api", "checkSysPassword"}, call("nw_check_sys_password"), nil) + page.leaf = true + page = entry({"api", "setpasswd"}, call("set_passwd"), nil, nil) + page.leaf = true + + page = entry({"api", "downloadstart"}, call("nw_download_task_start"), nil, nil) + page.leaf = true + page = entry({"api", "getActiveList"}, call("nw_get_active_list"), nil, nil) + page.leaf = true + page = entry({"api", "getHistoryList"}, call("nw_get_history_list"), nil, nil) + page.leaf = true + page = entry({"api", "operateTask"}, call("nw_download_task_operate"), nil, nil) + page.leaf = true + page = entry({"api", "getPauseList"}, call("nw_get_pause_list"), nil, nil) + page.leaf = true + page = entry({"api", "thunder_get_bind_code"}, call("nw_thunder_get_bind_code"), nil, nil) + page.leaf = true + + page = entry({"api", "batchFileCompareUpload"}, call("batchfile_compare_upload"), nil, nil) + page.leaf = true + page = entry({"api", "batchFileCheckList"}, call("batchfile_checklist"), nil, nil) + page.leaf = true + page = entry({"api", "getFilesList"}, call("getFilesList"), nil, nil) + page.leaf = true + --page = entry({"api", "setPPPoE"}, call("set_pppoe"), nil) + --page.leaf = true + + page = entry({"api", "checkupgrade"}, call("nw_check_upgrade"), nil) + page.leaf = true + page = entry({"api", "doupgrade"}, call("nw_do_upgrade"), nil) + page.leaf = true + + page = entry({"api", "setsmbsingleswitch"}, call("setsmbsingleswitch"),nil) + page.leaf = true + page = entry({"api", "setsmbswitch"}, call("nw_set_smbswitch"), nil) + page.leaf = true + page = entry({"api", "getsmbsingleswitch"}, call("getsmbsingleswitch"),nil) + page.leaf = true + page = entry({"api", "getsmbswitch"}, call("nw_get_smbswitch"), nil) + page.leaf = true + + page = entry({"api", "scanBleSwitch"}, call("nw_scan_ble_switch"), nil) + page.leaf = true + page = entry({"api", "getBleDeviceList"}, call("nw_get_ble_device_list"), nil) + page.leaf = true + page = entry({"api", "addMeshDevice"}, call("nw_add_ble_mesh_device"), nil) + page.leaf = true + page = entry({"api", "removeBleFromMesh"}, call("nw_remove_ble_from_mesh"), nil) + page.leaf = true + page = entry({"api", "getMeshDeviceDetail"}, call("nw_get_ble_device_status"), nil) + page.leaf = true + page = entry({"api", "getMeshDeviceList"}, call("nw_get_mesh_device_list"), nil) + page.leaf = true + page = entry({"api", "dismissMesh"}, call("nw_dismiss_mesh"), nil) + page.leaf = true + page = entry({"api", "setMeshDeviceAttr"}, call("nw_set_mesh_device_attr"), nil) + page.leaf = true + page = entry({"api", "rebootMeshDevice"}, call("nw_reboot_mesh_device"), nil) + page.leaf = true + page = entry({"api", "unmeshAllDevice"}, call("nw_unmesh_all_device"), nil) + page.leaf = true + page = entry({"api", "setMeshDeviceTimer"}, call("nw_set_mesh_device_timer"), nil) + page.leaf = true + page = entry({"api", "delMeshDeviceTimer"}, call("nw_del_mesh_device_timer"), nil) + page.leaf = true + page = entry({"api", "setMeshNetWorkPassword"}, call("nw_set_mesh_network_pwd"), nil) + page.leaf = true + page = entry({"api", "setLampBrightness"}, call("nw_set_lamp_brightness"), nil) + page.leaf = true + + +end + +function nw_check_upgrade() + local ret = check_upgrade() + luci.http.write(ret) +end + +function nw_do_upgrade() + local ret = {} + luci.http.status(200, "upgrading....") + ret["code"] = 2004 + ret["result"] = "upgrading...." + luci.http.write(data_to_json(ret)) + do_upgrade() +end + +function nw_real_time_net_speed() + luci.http.prepare_content("application/json") + local result = real_time_net_speed() + luci.http.write_json(result) +end + +function setsmbsingleswitch() + --local mac = luci.http.formvalue("mac") + --generate a white/black list to store this mac. + --if you want a mac not rw hdd, then write his mac into deny list. + --if you want a mac rw hdd, write his mac into allow list. + --modify smb.conf to ban this user's access. + --restart samba service +end + +function setsmbswitch() + local result = {} + local code = false + local onoff = luci.http.formvalue("smbswitch") + if (tonumber)(onoff) == 1 then + luci.sys.init.enable("samba") + exec_cmd_in_sh("sleep 1") + if luci.sys.init.enabled("samba") == true then + code = true + else + code = false + end + elseif (tonumber)(onoff) == 0 then + luci.sys.init.disable("samba") + exec_cmd_in_sh("sleep 1") + if luci.sys.init.enabled("samba") == true then + code = false + else + code = true + end + end + + result["result"] = code + luci.http.write_json(result) + +end + +function getsmbsingleswitch() +-- +end + +function getsmbswitch() + local smbswitch = {} + local code = false + code = luci.sys.init.enabled("samba") + smbswitch["smbswitch"] = code + luci.http.write_json(smbswitch) +end + +function nw_exec_reboot() + local ret = {} + ret["result"] = true + luci.http.write_json(ret) + exec_reboot() +end diff --git a/Me_Lua/h10/luci/controller/bs/index.lua b/Me_Lua/h10/luci/controller/bs/index.lua new file mode 100644 index 0000000..bb93e3e --- /dev/null +++ b/Me_Lua/h10/luci/controller/bs/index.lua @@ -0,0 +1,149 @@ +module("luci.controller.bs.index", package.seeall) + + +local arpmon = require "meizu.arpmon" +local bfs = require "meizu.bfs" +local btfs = require "meizu.btfs" + +nw_get_bluetooth_info = btfs.nw_get_bluetooth_info +new_device_notify = arpmon.new_device_notify + +function index() + local root = node() + if not root.target then + root.target = alias("bs") + root.index = true + end + local page = node("bs") + --page.target = firstchild() + page.title = _("bs") + page.order = 10 + page.index = true + page = entry({"bs", "info"}, call("info"), nil, nil) + page.leaf = true + page = entry({"bs", "token"}, call("token"), nil, nil) + page.leaf = true + + page = entry({"bs", "newdevicenotify"}, call("new_device_notify"), nil) + page.leaf = true + + page = entry({"bs", "devip"}, call("devip"), nil, nil) + page.leaf = true + page = entry({"bs", "testip"}, call("testip"), nil, nil) + page.leaf = true + page = entry({"bs", "normip"}, call("normip"), nil, nil) + page.leaf = true + + page = entry({"bs", "apk"}, call("apk"), nil) + page.leaf = true + + page = entry({"bs", "getToken"}, call("get_token"), nil) + page.leaf = true + page = entry({"bs", "sysauth"}, call("sysauth"), nil) + page.leaf = true + + page = entry({"bs", "getBluetoothInfo"}, call("nw_get_bluetooth_info"), nil) + page.leaf = true + +end + +function info() + luci.http.prepare_content("application/json") + local result = bfs.sysinfo() + luci.http.write_json(result) +end + +function token() + luci.http.prepare_content("application/json") + local httpHandler = require("socket.http") + local usernm = luci.http.formvalue("username") + local passwd = luci.http.formvalue("password") + if usernm == nil and passwd == nil then + local sauth = require "luci.sauth" + local token = sauth.noAuthGetToken() + if token then + luci.http.write_json(token) + end + else + local ret = luci.sys.user.checkpasswd(usernm, passwd) + if ret == true then + local sauth = require "luci.sauth" + local token = sauth.noAuthGetToken() + if token then + luci.http.write_json(token) + end + end + end +end + +function show_hosts() + local lue = require"luci.util".exec + local cmd = "cat /etc/hosts" + local ret = lue(cmd) + luci.http.write(ret) +end + +function devip() + local lue = require"luci.util".exec + local cmd = "/usr/sbin/mzrts_ips.sh devip" + local ret = lue(cmd) + show_hosts() +end + +function normip() + local lue = require"luci.util".exec + local cmd = "/usr/sbin/mzrts_ips.sh" + local ret = lue(cmd) + show_hosts() +end + +function testip() + local lue = require"luci.util".exec + local cmd = "/usr/sbin/mzrts_ips.sh testip" + local ret = lue(cmd) + show_hosts() +end + +function apk() + local fn, fd, block + local cmd = "ls /www/apk_download/apk/*.apk | awk '{printf $1}'" + fd = io.popen(cmd) + fn = fd:read("*l") + fd:close() + if fn ~= nil then + fd = nixio.open(fn, "r") + luci.http.header('Content-Disposition', 'attachment; filename="%s"' % {nixio.fs.basename(fn)}) + luci.http.prepare_content("application/octet-stream") + while true do + block = fd:read(nixio.const.buffersize) + require "MZLog".log(3, debug.getinfo(1).currentline) + if (not block) or (#block == 0) then + require "MZLog".log(3, debug.getinfo(1).currentline) + break + else + luci.http.write(block) + end + end + fd:close() + end + luci.http.close() +end + +function sysauth() + local res = {} + local usernm = luci.http.formvalue("username") + local passwd = luci.http.formvalue("password") + res["result"] = luci.sys.user.checkpasswd(usernm, passwd) + luci.http.write_json(res) +end + +function get_token() + local res = {} + local sauth = require "luci.sauth" + local sess = luci.http.getcookie("sysauth") + sess = sess and sess:match("^[a-f0-9]*$") + local sdat = sauth.read(sess) + res["sysauth"] = sess + res["token"] = sdat.token + luci.http.write_json(res) +end diff --git a/Me_Lua/h10/luci/dispatcher.lua b/Me_Lua/h10/luci/dispatcher.lua new file mode 100644 index 0000000..a8b7fd1 --- /dev/null +++ b/Me_Lua/h10/luci/dispatcher.lua @@ -0,0 +1,965 @@ +--[[ +LuCI - Dispatcher + +Description: +The request dispatcher and module dispatcher generators + +FileId: +$Id$ + +License: +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +]]-- + +--- LuCI web dispatcher. +local fs = require "nixio.fs" +local sys = require "luci.sys" +local init = require "luci.init" +local util = require "luci.util" +local http = require "luci.http" +local nixio = require "nixio", require "nixio.util" + +module("luci.dispatcher", package.seeall) +context = util.threadlocal() +uci = require "luci.model.uci" +i18n = require "luci.i18n" +_M.fs = fs + +authenticator = {} + +-- Index table +local index = nil + +-- Fastindex +local fi + + +--- Build the URL relative to the server webroot from given virtual path. +-- @param ... Virtual path +-- @return Relative URL +function build_url(...) + local path = {...} + local url = { http.getenv("SCRIPT_NAME") or "" } + + local k, v + for k, v in pairs(context.urltoken) do + url[#url+1] = "/;" + url[#url+1] = http.urlencode(k) + url[#url+1] = "=" + url[#url+1] = http.urlencode(v) + end + + local p + for _, p in ipairs(path) do + if p:match("^[a-zA-Z0-9_%-%.%%/,;]+$") then + url[#url+1] = "/" + url[#url+1] = p + end + end + + return table.concat(url, "") +end + +--- Check whether a dispatch node shall be visible +-- @param node Dispatch node +-- @return Boolean indicating whether the node should be visible +function node_visible(node) + if node then + return not ( + (not node.title or #node.title == 0) or + (not node.target or node.hidden == true) or + (type(node.target) == "table" and node.target.type == "firstchild" and + (type(node.nodes) ~= "table" or not next(node.nodes))) + ) + end + return false +end + +--- Return a sorted table of visible childs within a given node +-- @param node Dispatch node +-- @return Ordered table of child node names +function node_childs(node) + local rv = { } + if node then + local k, v + for k, v in util.spairs(node.nodes, + function(a, b) + return (node.nodes[a].order or 100) + < (node.nodes[b].order or 100) + end) + do + if node_visible(v) then + rv[#rv+1] = k + end + end + end + return rv +end + + +--- Send a 404 error code and render the "error404" template if available. +-- @param message Custom error message (optional) +-- @return false +function error404(message) + luci.http.status(404, "Not Found") + message = message or "Not Found" + + require("luci.template") + if not luci.util.copcall(luci.template.render, "error404") then + luci.http.prepare_content("text/plain") + luci.http.write(message) + end + return false +end + +--- Send a 500 error code and render the "error500" template if available. +-- @param message Custom error message (optional)# +-- @return false +function error500(message) + luci.util.perror(message) + if not context.template_header_sent then + luci.http.status(500, "Internal Server Error") + luci.http.prepare_content("text/plain") + luci.http.write(message) + else + require("luci.template") + if not luci.util.copcall(luci.template.render, "error500", {message=message}) then + luci.http.prepare_content("text/plain") + luci.http.write(message) + end + end + return false +end + +function authenticator.htmlauth(validator, accs, default) + local user = luci.http.formvalue("username") + local pass = luci.http.formvalue("password") + + if user and validator(user, pass) then + return user + end + + require("luci.i18n") + require("luci.template") + context.path = {} + luci.template.render("sysauth", {duser=default, fuser=user}) + return false + +end + +--- Dispatch an HTTP request. +-- @param request LuCI HTTP Request object +function httpdispatch(request, prefix) + luci.http.context.request = request + + local r = {} + context.request = r + context.urltoken = {} + + local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true) + + if prefix then + for _, node in ipairs(prefix) do + r[#r+1] = node + end + end + + local tokensok = true + for node in pathinfo:gmatch("[^/]+") do + local tkey, tval + if tokensok then + tkey, tval = node:match(";(%w+)=([a-fA-F0-9]*)") + end + if tkey then + context.urltoken[tkey] = tval + else + tokensok = false + r[#r+1] = node + end + end + + local stat, err = util.coxpcall(function() + dispatch(context.request) + end, error500) + + luci.http.close() + + --context._disable_memtrace() +end + +--- Dispatches a LuCI virtual path. +-- @param request Virtual path +function dispatch(request) + --context._disable_memtrace = require "luci.debug".trap_memtrace("l") + require "MZLog".log(3, request) + local ctx = context + ctx.path = request + + local conf = require "luci.config" + assert(conf.main, + "/etc/config/luci seems to be corrupt, unable to find section 'main'") + + local lang = conf.main.lang or "auto" + if lang == "auto" then + lang = "zh_cn" + --[[ + [local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or "" + [for lpat in aclang:gmatch("[%w-]+") do + [ lpat = lpat and lpat:gsub("-", "_") + [ if conf.languages[lpat] then + [ lang = lpat + [ break + [ end + [end + ]] + end + require "luci.i18n".setlanguage(lang) + + local c = ctx.tree + local stat + if not c then + c = createtree() + end + + local track = {} + local args = {} + ctx.args = args + ctx.requestargs = ctx.requestargs or args + local n + local token = ctx.urltoken + local preq = {} + local freq = {} + + for i, s in ipairs(request) do + preq[#preq+1] = s + freq[#freq+1] = s + c = c.nodes[s] + n = i + if not c then + break + end + + util.update(track, c) + + if c.leaf then + break + end + end + + if c and c.leaf then + for j=n+1, #request do + args[#args+1] = request[j] + freq[#freq+1] = request[j] + end + end + + ctx.requestpath = ctx.requestpath or freq + ctx.path = preq + + if track.i18n then + i18n.loadc(track.i18n) + end + + -- Init template engine + if (c and c.index) or not track.notemplate then + local tpl = require("luci.template") + local media = track.mediaurlbase or luci.config.main.mediaurlbase + if not pcall(tpl.Template, "themes/%s/header" % fs.basename(media)) then + media = nil + for name, theme in pairs(luci.config.themes) do + if name:sub(1,1) ~= "." and pcall(tpl.Template, + "themes/%s/header" % fs.basename(theme)) then + media = theme + end + end + assert(media, "No valid theme found") + end + + local function _ifattr(cond, key, val) + if cond then + local env = getfenv(3) + local scope = (type(env.self) == "table") and env.self + return string.format( + ' %s="%s"', tostring(key), + luci.util.pcdata(tostring( val + or (type(env[key]) ~= "function" and env[key]) + or (scope and type(scope[key]) ~= "function" and scope[key]) + or "" )) + ) + else + return '' + end + end + + tpl.context.viewns = setmetatable({ + write = luci.http.write; + include = function(name) tpl.Template(name):render(getfenv(2)) end; + translate = i18n.translate; + translatef = i18n.translatef; + export = function(k, v) if tpl.context.viewns[k] == nil then tpl.context.viewns[k] = v end end; + striptags = util.striptags; + pcdata = util.pcdata; + media = media; + theme = fs.basename(media); + resource = luci.config.main.resourcebase; + ifattr = function(...) return _ifattr(...) end; + attr = function(...) return _ifattr(true, ...) end; + }, {__index=function(table, key) + if key == "controller" then + return build_url() + elseif key == "REQUEST_URI" then + return build_url(unpack(ctx.requestpath)) + else + return rawget(table, key) or _G[key] + end + end}) + end + + track.dependent = (track.dependent ~= false) + assert(not track.dependent or not track.auto, + "Access Violation\nThe page at '" .. table.concat(request, "/") .. "/' " .. + "has no parent node so the access to this location has been denied.\n" .. + "This is a software bug, please report this message at " .. + "http://luci.subsignal.org/trac/newticket" + ) + + local isremote = http.getenv("REMOTE_ADDR") == "127.0.0.1" + + if not isremote and track.sysauth then + local sauth = require "luci.sauth" + + local authen = type(track.sysauth_authenticator) == "function" + and track.sysauth_authenticator + or authenticator[track.sysauth_authenticator] + + local def = (type(track.sysauth) == "string") and track.sysauth + local accs = def and {track.sysauth} or track.sysauth + local sess = ctx.authsession + local verifytoken = false + if not sess then + sess = luci.http.getcookie("sysauth") + sess = sess and sess:match("^[a-f0-9]*$") + verifytoken = true + end + + local sdat = sauth.read(sess) + local user + + if sdat then + if not verifytoken or ctx.urltoken.stok == sdat.token then + user = sdat.user + end + else + local eu = http.getenv("HTTP_AUTH_USER") + local ep = http.getenv("HTTP_AUTH_PASS") + if eu and ep and luci.sys.user.checkpasswd(eu, ep) then + authen = function() return eu end + end + end + + if not util.contains(accs, user) then + if authen then + ctx.urltoken.stok = nil + local user, sess = authen(luci.sys.user.checkpasswd, accs, def) + if not user or not util.contains(accs, user) then + return + else + local sid = sess or luci.sys.uniqueid(16) + if not sess then + local token = luci.sys.uniqueid(16) + sauth.reap() + sauth.write(sid, { + user=user, + token=token, + secret=luci.sys.uniqueid(16) + }) + ctx.urltoken.stok = token + end + luci.http.header("Set-Cookie", "sysauth=" .. sid.."; path="..build_url()) + ctx.authsession = sid + ctx.authuser = user + end + else + luci.http.status(403, "Forbidden") + return + end + else + ctx.authsession = sess + ctx.authuser = user + end + end + + if track.setgroup then + luci.sys.process.setgroup(track.setgroup) + end + + if track.setuser then + luci.sys.process.setuser(track.setuser) + end + + local target = nil + if c then + if type(c.target) == "function" then + target = c.target + elseif type(c.target) == "table" then + target = c.target.target + end + end + + if c and (c.index or type(target) == "function") then + ctx.dispatched = c + ctx.requested = ctx.requested or ctx.dispatched + end + + if c and c.index then + local tpl = require "luci.template" + + if util.copcall(tpl.render, "indexer", {}) then + return true + end + end + + if type(target) == "function" then + util.copcall(function() + local oldenv = getfenv(target) + local module = require(c.module) + local env = setmetatable({}, {__index= + + function(tbl, key) + return rawget(tbl, key) or module[key] or oldenv[key] + end}) + + setfenv(target, env) + end) + + local ok, err + if type(c.target) == "table" then + ok, err = util.copcall(target, c.target, unpack(args)) + else + ok, err = util.copcall(target, unpack(args)) + end + assert(ok, + "Failed to execute " .. (type(c.target) == "function" and "function" or c.target.type or "unknown") .. + " dispatcher target for entry '/" .. table.concat(request, "/") .. "'.\n" .. + "The called action terminated with an exception:\n" .. tostring(err or "(unknown)")) + else + local root = node() + if not root or not root.target then + error404("No root node was registered, this usually happens if no module was installed.\n" .. + "Install luci-mod-admin-full and retry. " .. + "If the module is already installed, try removing the /tmp/luci-indexcache file.") + else + error404("No page is registered at '/" .. table.concat(request, "/") .. "'.\n" .. + "If this url belongs to an extension, make sure it is properly installed.\n" .. + "If the extension was recently installed, try removing the /tmp/luci-indexcache file.") + end + end +end + +--- Generate the dispatching index using the best possible strategy. +function createindex() + local path = luci.util.libpath() .. "/controller/" + local suff = { ".lua", ".lua.gz" } + + if luci.util.copcall(require, "luci.fastindex") then + createindex_fastindex(path, suff) + else + createindex_plain(path, suff) + end +end + +--- Generate the dispatching index using the fastindex C-indexer. +-- @param path Controller base directory +-- @param suffixes Controller file suffixes +function createindex_fastindex(path, suffixes) + index = {} + + if not fi then + fi = luci.fastindex.new("index") + for _, suffix in ipairs(suffixes) do + fi.add(path .. "*" .. suffix) + fi.add(path .. "*/*" .. suffix) + end + end + fi.scan() + + for k, v in pairs(fi.indexes) do + index[v[2]] = v[1] + end +end + +--- Generate the dispatching index using the native file-cache based strategy. +-- @param path Controller base directory +-- @param suffixes Controller file suffixes +function createindex_plain(path, suffixes) + local controllers = { } + for _, suffix in ipairs(suffixes) do + nixio.util.consume((fs.glob(path .. "*" .. suffix)), controllers) + nixio.util.consume((fs.glob(path .. "*/*" .. suffix)), controllers) + end + + if indexcache then + local cachedate = fs.stat(indexcache, "mtime") + if cachedate then + local realdate = 0 + for _, obj in ipairs(controllers) do + local omtime = fs.stat(obj, "mtime") + realdate = (omtime and omtime > realdate) and omtime or realdate + end + + if cachedate > realdate then + assert( + sys.process.info("uid") == fs.stat(indexcache, "uid") + and fs.stat(indexcache, "modestr") == "rw-------", + "Fatal: Indexcache is not sane!" + ) + + index = loadfile(indexcache)() + return index + end + end + end + + index = {} + + for i,c in ipairs(controllers) do + local modname = "luci.controller." .. c:sub(#path+1, #c):gsub("/", ".") + for _, suffix in ipairs(suffixes) do + modname = modname:gsub(suffix.."$", "") + end + + local mod = require(modname) + assert(mod ~= true, + "Invalid controller file found\n" .. + "The file '" .. c .. "' contains an invalid module line.\n" .. + "Please verify whether the module name is set to '" .. modname .. + "' - It must correspond to the file path!") + + local idx = mod.index + assert(type(idx) == "function", + "Invalid controller file found\n" .. + "The file '" .. c .. "' contains no index() function.\n" .. + "Please make sure that the controller contains a valid " .. + "index function and verify the spelling!") + + index[modname] = idx + end + + if indexcache then + local f = nixio.open(indexcache, "w", 600) + f:writeall(util.get_bytecode(index)) + f:close() + end +end + +--- Create the dispatching tree from the index. +-- Build the index before if it does not exist yet. +function createtree() + if not index then + createindex() + end + + local ctx = context + local tree = {nodes={}, inreq=true} + local modi = {} + + ctx.treecache = setmetatable({}, {__mode="v"}) + ctx.tree = tree + ctx.modifiers = modi + + -- Load default translation + require "luci.i18n".loadc("base") + + local scope = setmetatable({}, {__index = luci.dispatcher}) + + for k, v in pairs(index) do + scope._NAME = k + setfenv(v, scope) + v() + end + + local function modisort(a,b) + return modi[a].order < modi[b].order + end + + for _, v in util.spairs(modi, modisort) do + scope._NAME = v.module + setfenv(v.func, scope) + v.func() + end + + return tree +end + +--- Register a tree modifier. +-- @param func Modifier function +-- @param order Modifier order value (optional) +function modifier(func, order) + context.modifiers[#context.modifiers+1] = { + func = func, + order = order or 0, + module + = getfenv(2)._NAME + } +end + +--- Clone a node of the dispatching tree to another position. +-- @param path Virtual path destination +-- @param clone Virtual path source +-- @param title Destination node title (optional) +-- @param order Destination node order value (optional) +-- @return Dispatching tree node +function assign(path, clone, title, order) + local obj = node(unpack(path)) + obj.nodes = nil + obj.module = nil + + obj.title = title + obj.order = order + + setmetatable(obj, {__index = _create_node(clone)}) + + return obj +end + +--- Create a new dispatching node and define common parameters. +-- @param path Virtual path +-- @param target Target function to call when dispatched. +-- @param title Destination node title +-- @param order Destination node order value (optional) +-- @return Dispatching tree node +function entry(path, target, title, order) + local c = node(unpack(path)) + + c.target = target + c.title = title + c.order = order + c.module = getfenv(2)._NAME + + return c +end + +--- Fetch or create a dispatching node without setting the target module or +-- enabling the node. +-- @param ... Virtual path +-- @return Dispatching tree node +function get(...) + return _create_node({...}) +end + +--- Fetch or create a new dispatching node. +-- @param ... Virtual path +-- @return Dispatching tree node +function node(...) + local c = _create_node({...}) + + c.module = getfenv(2)._NAME + c.auto = nil + + return c +end + +function _create_node(path) + if #path == 0 then + return context.tree + end + + local name = table.concat(path, ".") + local c = context.treecache[name] + + if not c then + local last = table.remove(path) + local parent = _create_node(path) + + c = {nodes={}, auto=true} + -- the node is "in request" if the request path matches + -- at least up to the length of the node path + if parent.inreq and context.path[#path+1] == last then + c.inreq = true + end + parent.nodes[last] = c + context.treecache[name] = c + end + return c +end + +-- Subdispatchers -- + +function _firstchild() + local path = { unpack(context.path) } + local name = table.concat(path, ".") + local node = context.treecache[name] + + local lowest + if node and node.nodes and next(node.nodes) then + local k, v + for k, v in pairs(node.nodes) do + if not lowest or + (v.order or 100) < (node.nodes[lowest].order or 100) + then + lowest = k + end + end + end + + assert(lowest ~= nil, + "The requested node contains no childs, unable to redispatch") + + path[#path+1] = lowest + dispatch(path) +end + +--- Alias the first (lowest order) page automatically +function firstchild() + return { type = "firstchild", target = _firstchild } +end + +--- Create a redirect to another dispatching node. +-- @param ... Virtual path destination +function alias(...) + local req = {...} + return function(...) + for _, r in ipairs({...}) do + req[#req+1] = r + end + + dispatch(req) + end +end + +--- Rewrite the first x path values of the request. +-- @param n Number of path values to replace +-- @param ... Virtual path to replace removed path values with +function rewrite(n, ...) + local req = {...} + return function(...) + local dispatched = util.clone(context.dispatched) + + for i=1,n do + table.remove(dispatched, 1) + end + + for i, r in ipairs(req) do + table.insert(dispatched, i, r) + end + + for _, r in ipairs({...}) do + dispatched[#dispatched+1] = r + end + + dispatch(dispatched) + end +end + + +local function _call(self, ...) + local func = getfenv()[self.name] + assert(func ~= nil, + 'Cannot resolve function "' .. self.name .. '". Is it misspelled or local?') + + assert(type(func) == "function", + 'The symbol "' .. self.name .. '" does not refer to a function but data ' .. + 'of type "' .. type(func) .. '".') + + if #self.argv > 0 then + return func(unpack(self.argv), ...) + else + return func(...) + end +end + +--- Create a function-call dispatching target. +-- @param name Target function of local controller +-- @param ... Additional parameters passed to the function +function call(name, ...) + return {type = "call", argv = {...}, name = name, target = _call} +end + + +local _template = function(self, ...) + require "luci.template".render(self.view) +end + +--- Create a template render dispatching target. +-- @param name Template to be rendered +function template(name) + return {type = "template", view = name, target = _template} +end + + +local function _cbi(self, ...) + local cbi = require "luci.cbi" + local tpl = require "luci.template" + local http = require "luci.http" + + local config = self.config or {} + local maps = cbi.load(self.model, ...) + + local state = nil + + for i, res in ipairs(maps) do + res.flow = config + local cstate = res:parse() + if cstate and (not state or cstate < state) then + state = cstate + end + end + + local function _resolve_path(path) + return type(path) == "table" and build_url(unpack(path)) or path + end + + if config.on_valid_to and state and state > 0 and state < 2 then + http.redirect(_resolve_path(config.on_valid_to)) + return + end + + if config.on_changed_to and state and state > 1 then + http.redirect(_resolve_path(config.on_changed_to)) + return + end + + if config.on_success_to and state and state > 0 then + http.redirect(_resolve_path(config.on_success_to)) + return + end + + if config.state_handler then + if not config.state_handler(state, maps) then + return + end + end + + http.header("X-CBI-State", state or 0) + + if not config.noheader then + tpl.render("cbi/header", {state = state}) + end + + local redirect + local messages + local applymap = false + local pageaction = true + local parsechain = { } + + for i, res in ipairs(maps) do + if res.apply_needed and res.parsechain then + local c + for _, c in ipairs(res.parsechain) do + parsechain[#parsechain+1] = c + end + applymap = true + end + + if res.redirect then + redirect = redirect or res.redirect + end + + if res.pageaction == false then + pageaction = false + end + + if res.message then + messages = messages or { } + messages[#messages+1] = res.message + end + end + + for i, res in ipairs(maps) do + res:render({ + firstmap = (i == 1), + applymap = applymap, + redirect = redirect, + messages = messages, + pageaction = pageaction, + parsechain = parsechain + }) + end + + if not config.nofooter then + tpl.render("cbi/footer", { + flow = config, + pageaction = pageaction, + redirect = redirect, + state = state, + autoapply = config.autoapply + }) + end +end + +--- Create a CBI model dispatching target. +-- @param model CBI model to be rendered +function cbi(model, config) + return {type = "cbi", config = config, model = model, target = _cbi} +end + + +local function _arcombine(self, ...) + local argv = {...} + local target = #argv > 0 and self.targets[2] or self.targets[1] + setfenv(target.target, self.env) + target:target(unpack(argv)) +end + +--- Create a combined dispatching target for non argv and argv requests. +-- @param trg1 Overview Target +-- @param trg2 Detail Target +function arcombine(trg1, trg2) + return {type = "arcombine", env = getfenv(), target = _arcombine, targets = {trg1, trg2}} +end + + +local function _form(self, ...) + local cbi = require "luci.cbi" + local tpl = require "luci.template" + local http = require "luci.http" + + local maps = luci.cbi.load(self.model, ...) + local state = nil + + for i, res in ipairs(maps) do + local cstate = res:parse() + if cstate and (not state or cstate < state) then + state = cstate + end + end + + http.header("X-CBI-State", state or 0) + tpl.render("header") + for i, res in ipairs(maps) do + res:render() + end + tpl.render("footer") +end + +--- Create a CBI form model dispatching target. +-- @param model CBI form model tpo be rendered +function form(model) + return {type = "cbi", model = model, target = _form} +end + +--- Access the luci.i18n translate() api. +-- @class function +-- @name translate +-- @param text Text to translate +translate = i18n.translate + +--- No-op function used to mark translation entries for menu labels. +-- This function does not actually translate the given argument but +-- is used by build/i18n-scan.pl to find translatable entries. +function _(text) + return text +end diff --git a/Me_Lua/h10/luci/model/network.lua b/Me_Lua/h10/luci/model/network.lua new file mode 100644 index 0000000..41b0e99 --- /dev/null +++ b/Me_Lua/h10/luci/model/network.lua @@ -0,0 +1,1632 @@ +--[[ +LuCI - Network model + +Copyright 2009-2010 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +]]-- + +local type, next, pairs, ipairs, loadfile, table + = type, next, pairs, ipairs, loadfile, table + +local tonumber, tostring, math = tonumber, tostring, math + +local require = require + +local bus = require "ubus" +local nxo = require "nixio" +local nfs = require "nixio.fs" +local ipc = require "luci.ip" +local sys = require "luci.sys" +local utl = require "luci.util" +local dsp = require "luci.dispatcher" +local uci = require "luci.model.uci" +local lng = require "luci.i18n" + +module "luci.model.network" + + +IFACE_PATTERNS_VIRTUAL = { } +IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^lo$" } +IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" } + + +protocol = utl.class() + +local _protocols = { } + +local _interfaces, _bridge, _switch, _tunnel +local _ubus, _ubusnetcache, _ubusdevcache, _ubuswificache +local _uci_real, _uci_state + +function _filter(c, s, o, r) + local val = _uci_real:get(c, s, o) + if val then + local l = { } + if type(val) == "string" then + for val in val:gmatch("%S+") do + if val ~= r then + l[#l+1] = val + end + end + if #l > 0 then + _uci_real:set(c, s, o, table.concat(l, " ")) + else + _uci_real:delete(c, s, o) + end + elseif type(val) == "table" then + for _, val in ipairs(val) do + if val ~= r then + l[#l+1] = val + end + end + if #l > 0 then + _uci_real:set(c, s, o, l) + else + _uci_real:delete(c, s, o) + end + end + end +end + +function _append(c, s, o, a) + local val = _uci_real:get(c, s, o) or "" + if type(val) == "string" then + local l = { } + for val in val:gmatch("%S+") do + if val ~= a then + l[#l+1] = val + end + end + l[#l+1] = a + _uci_real:set(c, s, o, table.concat(l, " ")) + elseif type(val) == "table" then + local l = { } + for _, val in ipairs(val) do + if val ~= a then + l[#l+1] = val + end + end + l[#l+1] = a + _uci_real:set(c, s, o, l) + end +end + +function _stror(s1, s2) + if not s1 or #s1 == 0 then + return s2 and #s2 > 0 and s2 + else + return s1 + end +end + +function _get(c, s, o) + return _uci_real:get(c, s, o) +end + +function _set(c, s, o, v) + if v ~= nil then + if type(v) == "boolean" then v = v and "1" or "0" end + return _uci_real:set(c, s, o, v) + else + return _uci_real:delete(c, s, o) + end +end + +function _wifi_iface(x) + local _, p + for _, p in ipairs(IFACE_PATTERNS_WIRELESS) do + if x:match(p) then + return true + end + end + return false +end + +function _wifi_state(key, val, field) + if not next(_ubuswificache) then + _ubuswificache = _ubus:call("network.wireless", "status", {}) or {} + end + + local radio, radiostate + for radio, radiostate in pairs(_ubuswificache) do + local ifc, ifcstate + for ifc, ifcstate in pairs(radiostate.interfaces) do + if ifcstate[key] == val then + return ifcstate[field] + end + end + end +end + +function _wifi_lookup(ifn) + -- got a radio#.network# pseudo iface, locate the corresponding section + local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$") + if radio and ifnidx then + local sid = nil + local num = 0 + + ifnidx = tonumber(ifnidx) + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device == radio then + num = num + 1 + if num == ifnidx then + sid = s['.name'] + return false + end + end + end) + + return sid + + -- looks like wifi, try to locate the section via state vars + elseif _wifi_iface(ifn) then + local sid = _wifi_state("ifname", ifn, "section") + if not sid then + _uci_state:foreach("wireless", "wifi-iface", + function(s) + if s.ifname == ifn then + sid = s['.name'] + return false + end + end) + end + + return sid + end +end + +function _iface_virtual(x) + local _, p + for _, p in ipairs(IFACE_PATTERNS_VIRTUAL) do + if x:match(p) then + return true + end + end + return false +end + +function _iface_ignore(x) + local _, p + for _, p in ipairs(IFACE_PATTERNS_IGNORE) do + if x:match(p) then + return true + end + end + return _iface_virtual(x) +end + + +function init(cursor) + _uci_real = cursor or _uci_real or uci.cursor() + _uci_state = _uci_real:substate() + + _interfaces = { } + _bridge = { } + _switch = { } + _tunnel = { } + + _ubus = bus.connect() + _ubusnetcache = { } + _ubusdevcache = { } + _ubuswificache = { } + + -- read interface information + local n, i + for n, i in ipairs(nxo.getifaddrs()) do + local name = i.name:match("[^:]+") + local prnt = name:match("^([^%.]+)%.") + + if _iface_virtual(name) then + _tunnel[name] = true + end + + if _tunnel[name] or not _iface_ignore(name) then + _interfaces[name] = _interfaces[name] or { + idx = i.ifindex or n, + name = name, + rawname = i.name, + flags = { }, + ipaddrs = { }, + ip6addrs = { } + } + + if prnt then + _switch[name] = true + _switch[prnt] = true + end + + if i.family == "packet" then + _interfaces[name].flags = i.flags + _interfaces[name].stats = i.data + _interfaces[name].macaddr = i.addr + elseif i.family == "inet" then + _interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask) + elseif i.family == "inet6" then + _interfaces[name].ip6addrs[#_interfaces[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask) + end + end + end + + -- read bridge informaton + local b, l + for l in utl.execi("brctl show") do + if not l:match("STP") then + local r = utl.split(l, "%s+", nil, true) + if #r == 4 then + b = { + name = r[1], + id = r[2], + stp = r[3] == "yes", + ifnames = { _interfaces[r[4]] } + } + if b.ifnames[1] then + b.ifnames[1].bridge = b + end + _bridge[r[1]] = b + elseif b then + b.ifnames[#b.ifnames+1] = _interfaces[r[2]] + b.ifnames[#b.ifnames].bridge = b + end + end + end + + return _M +end + +function save(self, ...) + _uci_real:save(...) + _uci_real:load(...) +end + +function commit(self, ...) + _uci_real:commit(...) + _uci_real:load(...) +end + +function ifnameof(self, x) + if utl.instanceof(x, interface) then + return x:name() + elseif utl.instanceof(x, protocol) then + return x:ifname() + elseif type(x) == "string" then + return x:match("^[^:]+") + end +end + +function get_protocol(self, protoname, netname) + local v = _protocols[protoname] + if v then + return v(netname or "__dummy__") + end +end + +function get_protocols(self) + local p = { } + local _, v + for _, v in ipairs(_protocols) do + p[#p+1] = v("__dummy__") + end + return p +end + +function register_protocol(self, protoname) + local proto = utl.class(protocol) + + function proto.__init__(self, name) + self.sid = name + end + + function proto.proto(self) + return protoname + end + + _protocols[#_protocols+1] = proto + _protocols[protoname] = proto + + return proto +end + +function register_pattern_virtual(self, pat) + IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat +end + + +function has_ipv6(self) + return nfs.access("/proc/net/ipv6_route") +end + +function add_network(self, n, options) + local oldnet = self:get_network(n) + if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then + if _uci_real:section("network", "interface", n, options) then + return network(n) + end + elseif oldnet and oldnet:is_empty() then + if options then + local k, v + for k, v in pairs(options) do + oldnet:set(k, v) + end + end + return oldnet + end +end + +function get_network(self, n) + if n and _uci_real:get("network", n) == "interface" then + return network(n) + end +end + +function get_networks(self) + local nets = { } + local nls = { } + + _uci_real:foreach("network", "interface", + function(s) + nls[s['.name']] = network(s['.name']) + end) + + local n + for n in utl.kspairs(nls) do + nets[#nets+1] = nls[n] + end + + return nets +end + +function del_network(self, n) + local r = _uci_real:delete("network", n) + if r then + _uci_real:delete_all("network", "alias", + function(s) return (s.interface == n) end) + + _uci_real:delete_all("network", "route", + function(s) return (s.interface == n) end) + + _uci_real:delete_all("network", "route6", + function(s) return (s.interface == n) end) + + _uci_real:foreach("wireless", "wifi-iface", + function(s) + local net + local rest = { } + for net in utl.imatch(s.network) do + if net ~= n then + rest[#rest+1] = net + end + end + if #rest > 0 then + _uci_real:set("wireless", s['.name'], "network", + table.concat(rest, " ")) + else + _uci_real:delete("wireless", s['.name'], "network") + end + end) + end + return r +end + +function rename_network(self, old, new) + local r + if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then + r = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old)) + + if r then + _uci_real:foreach("network", "alias", + function(s) + if s.interface == old then + _uci_real:set("network", s['.name'], "interface", new) + end + end) + + _uci_real:foreach("network", "route", + function(s) + if s.interface == old then + _uci_real:set("network", s['.name'], "interface", new) + end + end) + + _uci_real:foreach("network", "route6", + function(s) + if s.interface == old then + _uci_real:set("network", s['.name'], "interface", new) + end + end) + + _uci_real:foreach("wireless", "wifi-iface", + function(s) + local net + local list = { } + for net in utl.imatch(s.network) do + if net == old then + list[#list+1] = new + else + list[#list+1] = net + end + end + if #list > 0 then + _uci_real:set("wireless", s['.name'], "network", + table.concat(list, " ")) + end + end) + + _uci_real:delete("network", old) + end + end + return r or false +end + +function get_interface(self, i) + if _interfaces[i] or _wifi_iface(i) then + return interface(i) + else + local ifc + local num = { } + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device then + num[s.device] = num[s.device] and num[s.device] + 1 or 1 + if s['.name'] == i then + ifc = interface( + "%s.network%d" %{s.device, num[s.device] }) + return false + end + end + end) + return ifc + end +end + +function get_interfaces(self) + local iface + local ifaces = { } + local seen = { } + local nfs = { } + local baseof = { } + + -- find normal interfaces + _uci_real:foreach("network", "interface", + function(s) + for iface in utl.imatch(s.ifname) do + if not _iface_ignore(iface) and not _wifi_iface(iface) then + seen[iface] = true + nfs[iface] = interface(iface) + end + end + end) + + for iface in utl.kspairs(_interfaces) do + if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then + nfs[iface] = interface(iface) + end + end + + -- find vlan interfaces + _uci_real:foreach("network", "switch_vlan", + function(s) + if not s.device then + return + end + + local base = baseof[s.device] + if not base then + if not s.device:match("^eth%d") then + local l + for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do + if not base then + base = l:match("^%w+: (%w+)") + end + end + if not base or not base:match("^eth%d") then + base = "eth0" + end + else + base = s.device + end + baseof[s.device] = base + end + + local vid = tonumber(s.vid or s.vlan) + if vid ~= nil and vid >= 0 and vid <= 4095 then + local iface = "%s.%d" %{ base, vid } + if not seen[iface] then + seen[iface] = true + nfs[iface] = interface(iface) + end + end + end) + + for iface in utl.kspairs(nfs) do + ifaces[#ifaces+1] = nfs[iface] + end + + -- find wifi interfaces + local num = { } + local wfs = { } + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device then + num[s.device] = num[s.device] and num[s.device] + 1 or 1 + local i = "%s.network%d" %{ s.device, num[s.device] } + wfs[i] = interface(i) + end + end) + + for iface in utl.kspairs(wfs) do + ifaces[#ifaces+1] = wfs[iface] + end + + return ifaces +end + +function ignore_interface(self, x) + return _iface_ignore(x) +end + +function get_wifidev(self, dev) + if _uci_real:get("wireless", dev) == "wifi-device" then + return wifidev(dev) + end +end + +function get_wifidevs(self) + local devs = { } + local wfd = { } + + _uci_real:foreach("wireless", "wifi-device", + function(s) wfd[#wfd+1] = s['.name'] end) + + local dev + for _, dev in utl.vspairs(wfd) do + devs[#devs+1] = wifidev(dev) + end + + return devs +end + +function get_wifinet(self, net) + local wnet = _wifi_lookup(net) + if wnet then + return wifinet(wnet) + end +end + +function add_wifinet(self, net, options) + if type(options) == "table" and options.device and + _uci_real:get("wireless", options.device) == "wifi-device" + then + local wnet = _uci_real:section("wireless", "wifi-iface", nil, options) + return wifinet(wnet) + end +end + +function del_wifinet(self, net) + local wnet = _wifi_lookup(net) + if wnet then + _uci_real:delete("wireless", wnet) + return true + end + return false +end + +function get_status_by_route(self, addr, mask) + local _, object + for _, object in ipairs(_ubus:objects()) do + local net = object:match("^network%.interface%.(.+)") + if net then + local s = _ubus:call(object, "status", {}) + if s and s.route then + local rt + for _, rt in ipairs(s.route) do + if not rt.table and rt.target == addr and rt.mask == mask then + return net, s + end + end + end + end + end +end + +function get_status_by_address(self, addr) + local _, object + for _, object in ipairs(_ubus:objects()) do + local net = object:match("^network%.interface%.(.+)") + if net then + local s = _ubus:call(object, "status", {}) + if s and s['ipv4-address'] then + local a + for _, a in ipairs(s['ipv4-address']) do + if a.address == addr then + return net, s + end + end + end + if s and s['ipv6-address'] then + local a + for _, a in ipairs(s['ipv6-address']) do + if a.address == addr then + return net, s + end + end + end + end + end +end + +function get_wannet(self) + local net = self:get_status_by_route("0.0.0.0", 0) + return net and network(net) +end + +function get_wandev(self) + local _, stat = self:get_status_by_route("0.0.0.0", 0) + return stat and interface(stat.l3_device or stat.device) +end + +function get_wan6net(self) + local net = self:get_status_by_route("::", 0) + return net and network(net) +end + +function get_wan6dev(self) + local _, stat = self:get_status_by_route("::", 0) + return stat and interface(stat.l3_device or stat.device) +end + + +function network(name, proto) + if name then + local p = proto or _uci_real:get("network", name, "proto") + local c = p and _protocols[p] or protocol + return c(name) + end +end + +function protocol.__init__(self, name) + self.sid = name +end + +function protocol._get(self, opt) + local v = _uci_real:get("network", self.sid, opt) + if type(v) == "table" then + return table.concat(v, " ") + end + return v or "" +end + +function protocol._ubus(self, field) + if not _ubusnetcache[self.sid] then + _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid, + "status", { }) + end + if _ubusnetcache[self.sid] and field then + return _ubusnetcache[self.sid][field] + end + return _ubusnetcache[self.sid] +end + +function protocol.get(self, opt) + return _get("network", self.sid, opt) +end + +function protocol.set(self, opt, val) + return _set("network", self.sid, opt, val) +end + +function protocol.ifname(self) + local ifname + if self:is_floating() then + ifname = self:_ubus("l3_device") + else + ifname = self:_ubus("device") + end + if not ifname then + local num = { } + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device then + num[s.device] = num[s.device] + and num[s.device] + 1 or 1 + + local net + for net in utl.imatch(s.network) do + if net == self.sid then + ifname = "%s.network%d" %{ s.device, num[s.device] } + return false + end + end + end + end) + end + return ifname +end + +function protocol.proto(self) + return "none" +end + +function protocol.get_i18n(self) + local p = self:proto() + if p == "none" then + return lng.translate("Unmanaged") + elseif p == "static" then + return lng.translate("Static address") + elseif p == "dhcp" then + return lng.translate("DHCP client") + else + return lng.translate("Unknown") + end +end + +function protocol.type(self) + return self:_get("type") +end + +function protocol.name(self) + return self.sid +end + +function protocol.uptime(self) + return self:_ubus("uptime") or 0 +end + +function protocol.expires(self) + local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired")) + local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime")) + if a and l then + l = l - (nxo.sysinfo().uptime - a) + return l > 0 and l or 0 + end + return -1 +end + +function protocol.metric(self) + return tonumber(_uci_state:get("network", self.sid, "metric")) or 0 +end + +function protocol.ipaddr(self) + local addrs = self:_ubus("ipv4-address") + return addrs and #addrs > 0 and addrs[1].address +end + +function protocol.netmask(self) + local addrs = self:_ubus("ipv4-address") + return addrs and #addrs > 0 and + ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string() +end + +function protocol.gwaddr(self) + local _, route + for _, route in ipairs(self:_ubus("route") or { }) do + if route.target == "0.0.0.0" and route.mask == 0 then + return route.nexthop + end + end +end + +function protocol.dnsaddrs(self) + local dns = { } + local _, addr + for _, addr in ipairs(self:_ubus("dns-server") or { }) do + if not addr:match(":") then + dns[#dns+1] = addr + end + end + return dns +end + +function protocol.ip6addr(self) + local addrs = self:_ubus("ipv6-address") + if addrs and #addrs > 0 then + return "%s/%d" %{ addrs[1].address, addrs[1].mask } + else + addrs = self:_ubus("ipv6-prefix-assignment") + if addrs and #addrs > 0 then + return "%s/%d" %{ addrs[1].address, addrs[1].mask } + end + end +end + +function protocol.gw6addr(self) + local _, route + for _, route in ipairs(self:_ubus("route") or { }) do + if route.target == "::" and route.mask == 0 then + return ipc.IPv6(route.nexthop):string() + end + end +end + +function protocol.dns6addrs(self) + local dns = { } + local _, addr + for _, addr in ipairs(self:_ubus("dns-server") or { }) do + if addr:match(":") then + dns[#dns+1] = addr + end + end + return dns +end + +function protocol.is_bridge(self) + return (not self:is_virtual() and self:type() == "bridge") +end + +function protocol.opkg_package(self) + return nil +end + +function protocol.is_installed(self) + return true +end + +function protocol.is_virtual(self) + return false +end + +function protocol.is_floating(self) + return false +end + +function protocol.is_empty(self) + if self:is_floating() then + return false + else + local rv = true + + if (self:_get("ifname") or ""):match("%S+") then + rv = false + end + + _uci_real:foreach("wireless", "wifi-iface", + function(s) + local n + for n in utl.imatch(s.network) do + if n == self.sid then + rv = false + return false + end + end + end) + + return rv + end +end + +function protocol.add_interface(self, ifname) + ifname = _M:ifnameof(ifname) + if ifname and not self:is_floating() then + -- if its a wifi interface, change its network option + local wif = _wifi_lookup(ifname) + if wif then + _append("wireless", wif, "network", self.sid) + + -- add iface to our iface list + else + _append("network", self.sid, "ifname", ifname) + end + end +end + +function protocol.del_interface(self, ifname) + ifname = _M:ifnameof(ifname) + if ifname and not self:is_floating() then + -- if its a wireless interface, clear its network option + local wif = _wifi_lookup(ifname) + if wif then _filter("wireless", wif, "network", self.sid) end + + -- remove the interface + _filter("network", self.sid, "ifname", ifname) + end +end + +function protocol.get_interface(self) + if self:is_virtual() then + _tunnel[self:proto() .. "-" .. self.sid] = true + return interface(self:proto() .. "-" .. self.sid, self) + elseif self:is_bridge() then + _bridge["br-" .. self.sid] = true + return interface("br-" .. self.sid, self) + else + local ifn = nil + local num = { } + for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do + ifn = ifn:match("^[^:/]+") + return ifn and interface(ifn, self) + end + ifn = nil + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device then + num[s.device] = num[s.device] and num[s.device] + 1 or 1 + + local net + for net in utl.imatch(s.network) do + if net == self.sid then + ifn = "%s.network%d" %{ s.device, num[s.device] } + return false + end + end + end + end) + return ifn and interface(ifn, self) + end +end + +function protocol.get_interfaces(self) + if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then + local ifaces = { } + + local ifn + local nfs = { } + for ifn in utl.imatch(self:get("ifname")) do + ifn = ifn:match("^[^:/]+") + nfs[ifn] = interface(ifn, self) + end + + for ifn in utl.kspairs(nfs) do + ifaces[#ifaces+1] = nfs[ifn] + end + + local num = { } + local wfs = { } + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device then + num[s.device] = num[s.device] and num[s.device] + 1 or 1 + + local net + for net in utl.imatch(s.network) do + if net == self.sid then + ifn = "%s.network%d" %{ s.device, num[s.device] } + wfs[ifn] = interface(ifn, self) + end + end + end + end) + + for ifn in utl.kspairs(wfs) do + ifaces[#ifaces+1] = wfs[ifn] + end + + return ifaces + end +end + +function protocol.contains_interface(self, ifname) + ifname = _M:ifnameof(ifname) + if not ifname then + return false + elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then + return true + elseif self:is_bridge() and "br-" .. self.sid == ifname then + return true + else + local ifn + for ifn in utl.imatch(self:get("ifname")) do + ifn = ifn:match("[^:]+") + if ifn == ifname then + return true + end + end + + local wif = _wifi_lookup(ifname) + if wif then + local n + for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do + if n == self.sid then + return true + end + end + end + end + + return false +end + +function protocol.adminlink(self) + return dsp.build_url("admin", "network", "network", self.sid) +end + +function protocol.get_option_value(self,name) + return self:_get(name) +end + +function protocol.status(self) + local iface = uci.cursor_state():get_all("network", self.sid) + local proto = iface["proto"] + local ifname = iface["ifname"] + local device = iface["device"] + local up = tonumber(iface["up"]) + if proto == "pppoe" then + if device == nil then + return "down" + end + if up == nil then + return "connection" + end + if up == 1 then + return "up" + end + elseif proto == "3g" then + if device ~= ifname and up==nil then + return "down" + end + if device == ifname and up == nil then + return "connection" + end + if up == 1 then + return "up" + end + elseif proto == "static" then + if up == nil then + return "down" + end + if up == 1 then + return "up" + end + elseif proto == "dhcp" then + if up == nil then + return "down" + end + if up == 1 then + return "up" + end + end + return "unkown" +end + +interface = utl.class() + +function interface.__init__(self, ifname, network) + local wif = _wifi_lookup(ifname) + if wif then + self.wif = wifinet(wif) + self.ifname = _wifi_state("section", wif, "ifname") + end + + self.ifname = self.ifname or ifname + self.dev = _interfaces[self.ifname] + self.network = network +end + +function interface._ubus(self, field) + if not _ubusdevcache[self.ifname] then + _ubusdevcache[self.ifname] = _ubus:call("network.device", "status", + { name = self.ifname }) + end + if _ubusdevcache[self.ifname] and field then + return _ubusdevcache[self.ifname][field] + end + return _ubusdevcache[self.ifname] +end + +function interface.name(self) + return self.wif and self.wif:ifname() or self.ifname +end + +function interface.mac(self) + return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper() +end + +function interface.ipaddrs(self) + return self.dev and self.dev.ipaddrs or { } +end + +function interface.ip6addrs(self) + return self.dev and self.dev.ip6addrs or { } +end + +function interface.type(self) + if self.wif or _wifi_iface(self.ifname) then + return "wifi" + elseif _bridge[self.ifname] then + return "bridge" + elseif _tunnel[self.ifname] then + return "tunnel" + elseif self.ifname:match("%.") then + return "vlan" + elseif _switch[self.ifname] then + return "switch" + else + return "ethernet" + end +end + +function interface.shortname(self) + if self.wif then + return "%s %q" %{ + self.wif:active_mode(), + self.wif:active_ssid() or self.wif:active_bssid() + } + else + return self.ifname + end +end + +function interface.get_i18n(self) + if self.wif then + return "%s: %s %q" %{ + lng.translate("Wireless Network"), + self.wif:active_mode(), + self.wif:active_ssid() or self.wif:active_bssid() + } + else + return "%s: %q" %{ self:get_type_i18n(), self:name() } + end +end + +function interface.get_type_i18n(self) + local x = self:type() + if x == "wifi" then + return lng.translate("Wireless Adapter") + elseif x == "bridge" then + return lng.translate("Bridge") + elseif x == "switch" then + return lng.translate("Ethernet Switch") + elseif x == "vlan" then + return lng.translate("VLAN Interface") + elseif x == "tunnel" then + return lng.translate("Tunnel Interface") + else + return lng.translate("Ethernet Adapter") + end +end + +function interface.adminlink(self) + if self.wif then + return self.wif:adminlink() + end +end + +function interface.ports(self) + local members = self:_ubus("bridge-members") + if members then + local _, iface + local ifaces = { } + for _, iface in ipairs(members) do + ifaces[#ifaces+1] = interface(iface) + end + end +end + +function interface.bridge_id(self) + if self.br then + return self.br.id + else + return nil + end +end + +function interface.bridge_stp(self) + if self.br then + return self.br.stp + else + return false + end +end + +function interface.is_up(self) + return self:_ubus("up") or false +end + +function interface.is_bridge(self) + return (self:type() == "bridge") +end + +function interface.is_bridgeport(self) + return self.dev and self.dev.bridge and true or false +end + +function interface.tx_bytes(self) + local stat = self:_ubus("statistics") + return stat and stat.tx_bytes or 0 +end + +function interface.rx_bytes(self) + local stat = self:_ubus("statistics") + return stat and stat.rx_bytes or 0 +end + +function interface.tx_packets(self) + local stat = self:_ubus("statistics") + return stat and stat.tx_packets or 0 +end + +function interface.rx_packets(self) + local stat = self:_ubus("statistics") + return stat and stat.rx_packets or 0 +end + +function interface.get_network(self) + return self:get_networks()[1] +end + +function interface.get_networks(self) + if not self.networks then + local nets = { } + local _, net + for _, net in ipairs(_M:get_networks()) do + if net:contains_interface(self.ifname) or + net:ifname() == self.ifname + then + nets[#nets+1] = net + end + end + table.sort(nets, function(a, b) return a.sid < b.sid end) + self.networks = nets + return nets + else + return self.networks + end +end + +function interface.get_wifinet(self) + return self.wif +end + + +wifidev = utl.class() + +function wifidev.__init__(self, dev) + self.sid = dev + self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { } +end + +function wifidev.get(self, opt) + return _get("wireless", self.sid, opt) +end + +function wifidev.set(self, opt, val) + return _set("wireless", self.sid, opt, val) +end + +function wifidev.name(self) + return self.sid +end + +function wifidev.hwmodes(self) + local l = self.iwinfo.hwmodelist + if l and next(l) then + return l + else + return { b = true, g = true } + end +end + +function wifidev.get_i18n(self) + local t = "Generic" + if self.iwinfo.type == "wl" then + t = "Broadcom" + elseif self.iwinfo.type == "madwifi" then + t = "Atheros" + end + + local m = "" + local l = self:hwmodes() + if l.a then m = m .. "a" end + if l.b then m = m .. "b" end + if l.g then m = m .. "g" end + if l.n then m = m .. "n" end + if l.ac then m = "ac" end + + return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() } +end + +function wifidev.is_up(self) + if _ubuswificache[self.sid] then + return (_ubuswificache[self.sid].up == true) + end + + local up = false + _uci_state:foreach("wireless", "wifi-iface", + function(s) + if s.device == self.sid then + if s.up == "1" then + up = true + return false + end + end + end) + + return up +end + +function wifidev.get_wifinet(self, net) + if _uci_real:get("wireless", net) == "wifi-iface" then + return wifinet(net) + else + local wnet = _wifi_lookup(net) + if wnet then + return wifinet(wnet) + end + end +end + +function wifidev.get_wifinets(self) + local nets = { } + + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device == self.sid then + nets[#nets+1] = wifinet(s['.name']) + end + end) + + return nets +end + +function wifidev.add_wifinet(self, options) + options = options or { } + options.device = self.sid + + local wnet = _uci_real:section("wireless", "wifi-iface", nil, options) + if wnet then + return wifinet(wnet, options) + end +end + +function wifidev.del_wifinet(self, net) + if utl.instanceof(net, wifinet) then + net = net.sid + elseif _uci_real:get("wireless", net) ~= "wifi-iface" then + net = _wifi_lookup(net) + end + + if net and _uci_real:get("wireless", net, "device") == self.sid then + _uci_real:delete("wireless", net) + return true + end + + return false +end + + +wifinet = utl.class() + +function wifinet.__init__(self, net, data) + self.sid = net + + local num = { } + local netid + _uci_real:foreach("wireless", "wifi-iface", + function(s) + if s.device then + num[s.device] = num[s.device] and num[s.device] + 1 or 1 + if s['.name'] == self.sid then + netid = "%s.network%d" %{ s.device, num[s.device] } + return false + end + end + end) + + local dev = _wifi_state("section", self.sid, "ifname") or netid + + self.netid = netid + self.wdev = dev + self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { } + self.iwdata = data or _uci_state:get_all("wireless", self.sid) or + _uci_real:get_all("wireless", self.sid) or { } +end + +function wifinet.get(self, opt) + return _get("wireless", self.sid, opt) +end + +function wifinet.set(self, opt, val) + return _set("wireless", self.sid, opt, val) +end + +function wifinet.mode(self) + return _uci_state:get("wireless", self.sid, "mode") or "ap" +end + +function wifinet.ssid(self) + return _uci_state:get("wireless", self.sid, "ssid") +end + +function wifinet.bssid(self) + return _uci_state:get("wireless", self.sid, "bssid") +end + +function wifinet.network(self) + return _uci_state:get("wifinet", self.sid, "network") +end + +function wifinet.id(self) + return self.netid +end + +function wifinet.name(self) + return self.sid +end + +function wifinet.ifname(self) + local ifname = self.iwinfo.ifname + if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then + ifname = self.wdev + end + return ifname +end + +function wifinet.get_device(self) + if self.iwdata.device then + return wifidev(self.iwdata.device) + end +end + +function wifinet.is_up(self) + local ifc = self:get_interface() + return (ifc and ifc:is_up() or false) +end + +function wifinet.active_mode(self) + local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap" + + if m == "ap" then m = "Master" + elseif m == "sta" then m = "Client" + elseif m == "adhoc" then m = "Ad-Hoc" + elseif m == "mesh" then m = "Mesh" + elseif m == "monitor" then m = "Monitor" + end + + return m +end + +function wifinet.active_mode_i18n(self) + return lng.translate(self:active_mode()) +end + +function wifinet.active_ssid(self) + return _stror(self.iwinfo.ssid, self.iwdata.ssid) +end + +function wifinet.active_bssid(self) + return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00" +end + +function wifinet.active_encryption(self) + local enc = self.iwinfo and self.iwinfo.encryption + return enc and enc.description or "-" +end + +function wifinet.assoclist(self) + return self.iwinfo.assoclist or { } +end + +function wifinet.frequency(self) + local freq = self.iwinfo.frequency + if freq and freq > 0 then + return "%.03f" % (freq / 1000) + end +end + +function wifinet.bitrate(self) + local rate = self.iwinfo.bitrate + if rate and rate > 0 then + return (rate / 1000) + end +end + +function wifinet.channel(self) + return self.iwinfo.channel or + tonumber(_uci_state:get("wireless", self.iwdata.device, "channel")) +end + +function wifinet.signal(self) + return self.iwinfo.signal or 0 +end + +function wifinet.noise(self) + return self.iwinfo.noise or 0 +end + +function wifinet.country(self) + return self.iwinfo.country or "00" +end + +function wifinet.txpower(self) + local pwr = (self.iwinfo.txpower or 0) + return pwr + self:txpower_offset() +end + +function wifinet.txpower_offset(self) + return self.iwinfo.txpower_offset or 0 +end + +function wifinet.signal_level(self, s, n) + if self:active_bssid() ~= "00:00:00:00:00:00" then + local signal = s or self:signal() + local noise = n or self:noise() + + if signal < 0 and noise < 0 then + local snr = -1 * (noise - signal) + return math.floor(snr / 5) + else + return 0 + end + else + return -1 + end +end + +function wifinet.signal_percent(self) + local qc = self.iwinfo.quality or 0 + local qm = self.iwinfo.quality_max or 0 + + if qc > 0 and qm > 0 then + return math.floor((100 / qm) * qc) + else + return 0 + end +end + +function wifinet.shortname(self) + return "%s %q" %{ + lng.translate(self:active_mode()), + self:active_ssid() or self:active_bssid() + } +end + +function wifinet.get_i18n(self) + return "%s: %s %q (%s)" %{ + lng.translate("Wireless Network"), + lng.translate(self:active_mode()), + self:active_ssid() or self:active_bssid(), + self:ifname() + } +end + +function wifinet.adminlink(self) + return dsp.build_url("admin", "network", "wireless", self.netid) +end + +function wifinet.get_network(self) + return self:get_networks()[1] +end + +function wifinet.get_networks(self) + local nets = { } + local net + for net in utl.imatch(tostring(self.iwdata.network)) do + if _uci_real:get("network", net) == "interface" then + nets[#nets+1] = network(net) + end + end + table.sort(nets, function(a, b) return a.sid < b.sid end) + return nets +end + +function wifinet.get_interface(self) + return interface(self:ifname()) +end + + +-- setup base protocols +_M:register_protocol("static") +_M:register_protocol("dhcp") +_M:register_protocol("none") + +-- load protocol extensions +local exts = nfs.dir(utl.libpath() .. "/model/network") +if exts then + local ext + for ext in exts do + if ext:match("%.lua$") then + require("luci.model.network." .. ext:gsub("%.lua$", "")) + end + end +end diff --git a/Me_Lua/h10/luci/sauth.lua b/Me_Lua/h10/luci/sauth.lua new file mode 100644 index 0000000..ec02be8 --- /dev/null +++ b/Me_Lua/h10/luci/sauth.lua @@ -0,0 +1,200 @@ +--[[ + +Session authentication +(c) 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +]]-- + +--- LuCI session library. +module("luci.sauth", package.seeall) +require("luci.util") +require("luci.sys") +require("luci.config") +local nixio = require "nixio", require "nixio.util" +local fs = require "nixio.fs" + + +luci.config.sauth = luci.config.sauth or {} +sessionpath = luci.config.sauth.sessionpath +sessiontime = tonumber(luci.config.sauth.sessiontime) or 15 * 60 + +--- Prepare session storage by creating the session directory. +function prepare() + fs.mkdir(sessionpath, 700) + if not sane() then + error("Security Exception: Session path is not sane!") + end +end + +local function _read(id) + local blob = fs.readfile(sessionpath .. "/" .. id) + return blob +end + +local function _write(id, data) + local tempid = luci.sys.uniqueid(16) + local tempfile = sessionpath .. "/" .. tempid + local sessfile = sessionpath .. "/" .. id + local f = nixio.open(tempfile, "w", 600) + f:writeall(data) + f:close() + fs.rename(tempfile, sessfile) +end + +local function _checkid(id) + return not not (id and #id == 32 and id:match("^[a-fA-F0-9]+$")) +end + +--- Write session data to a session file. +-- @param id Session identifier +-- @param data Session data table +function write(id, data) + if not sane() then + prepare() + end + + if not _checkid(id) then + return + end + + if type(data) ~= "table" then + return + end + + data.atime = luci.sys.uptime() + + _write(id, luci.util.get_bytecode(data)) +end + +--- Read a session and return its content. +-- @param id Session identifier +-- @return Session data table or nil if the given id is not found +function read(id) + if not id or #id == 0 then + return nil + end + + if not _checkid(id) then + return nil + end + + if not sane(sessionpath .. "/" .. id) then + return nil + end + + local blob = _read(id) + local func = loadstring(blob) + setfenv(func, {}) + + local sess = func() + if type(sess) ~= "table" then + return nil + end + + if sess.atime and sess.atime + sessiontime < luci.sys.uptime() then + kill(id) + return nil + end + + -- refresh atime in session + write(id, sess) + + return sess +end + +--- Check whether Session environment is sane. +-- @return Boolean status +function sane(file) + return luci.sys.process.info("uid") + == fs.stat(file or sessionpath, "uid") + and fs.stat(file or sessionpath, "modestr") + == (file and "rw-------" or "rwx------") +end + +--- Kills a session +-- @param id Session identifier +function kill(id) + if not _checkid(id) then + else + fs.unlink(sessionpath .. "/" .. id) + end +end + +--- Remove all expired session data files +function reap() + if sane() then + local id + for id in nixio.fs.dir(sessionpath) do + if _checkid(id) then + -- reading the session will kill it if it is expired + read(id) + end + end + end +end + +--- Get available session data +function available() + if sane() then + local id + for id in nixio.fs.dir(sessionpath) do + if _checkid(id) then + -- reading the session will kill it if it is expired + local available = read(id) + if available then + return available + end + end + end + end + return nil +end + +function genAuthToken() + local id = luci.sys.uniqueid(16) + local token = luci.sys.uniqueid(16) + write(id, { + user="root", + token=token, + secret=luci.sys.uniqueid(16) + }) + return id, read(id) +end + +function noAuthGetToken() + local id + local data + local ret = {} + if sessionpath then + local ids = nixio.fs.dir(sessionpath) + require "MZLog".log(3, debug.getinfo(1).currentline) + if not ids then + genAuthToken() + end + for id in nixio.fs.dir(sessionpath) do + if id then + read(id) + end + end + for id in nixio.fs.dir(sessionpath) do + if id then + ret["sysauth"] = id + ret["data"] = read(id) + return ret + end + end + require "MZLog".log(3, debug.getinfo(1).currentline) + id, data = genAuthToken() + ret["sysauth"] = id + ret["data"] = read(id) + return ret + end +end diff --git a/Me_Lua/h10/meizu/arpmon.lua b/Me_Lua/h10/meizu/arpmon.lua new file mode 100644 index 0000000..e0f7160 --- /dev/null +++ b/Me_Lua/h10/meizu/arpmon.lua @@ -0,0 +1,99 @@ +module("meizu.arpmon", package.seeall) +--network functions + +local cjson = require "cjson" +local lfs = require "lfs" +local bfs = require "meizu.bfs" +local dbfs = require "meizu.dbfs" +local RC = require "meizu.r10config" +local sipfs = require "meizu.sipfs" +local nwfs = require "meizu.nwfs" + +local lue = require("luci.util").exec + +local bind_router = bfs.bind_router +local data_to_json = bfs.data_to_json +local exec_cmd_in_sh = bfs.exec_cmd_in_sh +local exec_reboot = bfs.exec_reboot +local get_device_SN = bfs.get_device_SN +local get_device_version = bfs.get_device_version +local get_https_data = bfs.get_https_data +local rts_get_access_token = bfs.rts_get_access_token +local set_passwd = bfs.set_passwd +local silent_upgrade = bfs.silent_upgrade +local strsplit = bfs.strsplit + +local delete_arp_all_mac = dbfs.delete_arp_all_mac +local fetch_arp_mac = dbfs.fetch_arp_mac +local get_dev_nick_name = dbfs.get_dev_nick_name +local init_arp_table = dbfs.init_arp_table +local insert_arp_macip = dbfs.insert_arp_macip + +function new_device_notify() + + init_arp_table() + local ret = {} + local cmd = [[cat /proc/net/arp |grep br-lan|awk '{print $1","$4}']] + local ipmacs = {} + local devs = lue(cmd) + if devs ~= "" then + ipmacs = strsplit(devs, '\n') + end + local new_devs = {} + ipmacs[#ipmacs] = nil + local wifiDeviceDict = nwfs.getAllWifiConnetDeviceDict() + for k, v in pairs(ipmacs) do + local ipmac = strsplit(v, ',') + local ip = ipmac[1] + local mac = ipmac[2] + mac = string.upper(mac) + local wifiType = wifiDeviceDict[mac] + local data = dbfs.fetch_wireless_device_mac(mac) + if wifiType ~= nil then + --local res = dbfs.fetch_wireless_device_mac(mac) + if data == "" then + dbfs.insert_wireless_device_mac(mac) + end + else + local ret = dbfs.fetch_wire_device_mac(mac) + local res = nwfs.is_device_online(ip) + if res == false and ret == "" and data == "" then + dbfs.insert_wireless_device_mac(mac) + elseif res == true and ret == "" then + dbfs.insert_wire_device_mac(mac, ip) + end + end + + if ip ~= "" then + if fetch_arp_mac(mac) == "" then + table.insert(new_devs, v) + end + end + end + delete_arp_all_mac() + for k, v in pairs(ipmacs) do + local ipmac = strsplit(v, ',') + local ip = ipmac[1] + local mac = ipmac[2] + if ip ~= "" then + insert_arp_macip(mac, ip) + end + end + for k, v in pairs(new_devs) do + local ipmac = strsplit(v, ',') + local ip = ipmac[1] + local mac = ipmac[2] + if ip ~= "" then + local logtype = 1 + ret["mac_address"] = mac + local nickname = get_dev_nick_name(mac) + if nickname and nickname ~= "" then + ret["name"] = nickname + else + ret["name"] = ip + end + local res, code, headers, status = sipfs.upload_router_log(data_to_json(ret), logtype) + end + end + luci.http.write_json(ret) +end diff --git a/Me_Lua/h10/meizu/bfs.lua b/Me_Lua/h10/meizu/bfs.lua new file mode 100644 index 0000000..b62ae41 --- /dev/null +++ b/Me_Lua/h10/meizu/bfs.lua @@ -0,0 +1,511 @@ +module("meizu.bfs", package.seeall) +--API base functions + +local cjson = require "cjson" +local dbfs = require "meizu.dbfs" + +local delete_access_token = dbfs.delete_access_token + +function cal_str_md5(str) + local md5 = "" + local cmd = [[/bin/echo -n ']]..str + cmd = cmd..[['|/usr/bin/md5sum|/usr/bin/cut -d" " -f1]] + local fd = io.popen(cmd) + local ln = fd:read("*l") + if ln ~= nil then + md5 = ln + end + fd:close() + return md5 +end + +function strsplit(str, delim, maxNb) + local result = {} + if delim == nil then + delim = '\n' + end + if string.find(str, delim) == nil then + return { str } + end + if maxNb == nil or maxNb < 1 then + maxNb = 0 + end + local pat = "(.-)" .. delim .. "()" + local nb = 0 + local lastPos + for part, pos in string.gfind(str, pat) do + nb = nb + 1 + result[nb] = part + lastPos = pos + if nb == maxNb then break end + end + if nb ~= maxNb then + result[nb + 1] = string.sub(str, lastPos) + end + + return result +end + +function data_to_json(x) + local buf = "" + if x == nil then + return "" + elseif x == "" then + return '""' + elseif type(x) == "table" then + local k, v + if type(next(x)) == "number" then + buf = buf.."[ " + for k, v in ipairs(x) do + buf = buf..data_to_json(v) + if next(x, k) then + buf = buf..", " + end + end + buf = buf.." ]" + else + buf = buf.."{ " + for k, v in pairs(x) do + buf = buf..string.format("%q: " % k) + buf = buf..data_to_json(v) + if next(x, k) then + buf = buf..", " + end + end + buf = buf.." }" + end + elseif type(x) == "number" or type(x) == "boolean" then + if (x ~= x) then + buf = buf.."Number.NaN" + else + buf = buf..tostring(x) + end + else + buf = buf..string.format('"%s"' % tostring(x):gsub('[%z\1-\31]', function(c) return '\\u%04x' % c:byte(1) end)) + end + return buf +end + +function exec_cmd_in_sh(command) + local nio = require("nixio") + require "MZLog".log(3, command) + local pid = nio.fork() + if pid > 0 then + return + elseif pid == 0 then + nio.chdir("/") + local null = nio.open("/dev/null", "w+") + if null then + nio.dup(null, nio.stderr) + nio.dup(null, nio.stdout) + nio.dup(null, nio.stdin) + if null:fileno() > 2 then + null:close() + end + end + nio.exec("/bin/sh", "-c", command) + end +end + +--local get_https_data = function(url, data) return require("ssl.https").request(url, data) end +--return res, code, headers, status +function get_https_data(url, data) + if data ~= nil then + return require("ssl.https").request(url, data) + else + return require("ssl.https").request(url) + end +end + +function decodeURI(s) + local s = string.gsub(s, '%%(%x%x)', function(h) return string.char(tonumber(h, 16)) end) + return s +end + +function encodeURI(s) + local s = string.gsub(s, "([^%w%.%- ])", function(c) return string.format("%%%02X", string.byte(c)) end) + return string.gsub(s, " ", "+") +end + +function b64enc(data) + local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + return ((data:gsub('.', function(x) + local r,b='',x:byte() + for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end + return r; + end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) + if (#x < 6) then return '' end + local c=0 + for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end + return b:sub(c+1,c+1) + end)..({ '', '==', '=' })[#data%3+1]) +end + +function b64dec(data) + local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + data = string.gsub(data, '[^'..b..'=]', '') + return (data:gsub('.', function(x) + if (x == '=') then return '' end + local r,f='',(b:find(x)-1) + for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end + return r; + end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x) + if (#x ~= 8) then return '' end + local c=0 + for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end + return string.char(c) + end)) +end + +function exec_reboot() + --luci.sys.reboot() + exec_cmd_in_sh("reboot -f") +end + +function factory_reset() + --exec_cmd_in_sh("killall dropbear uhttpd; sleep 1; mtd erase nvram; mtd -r erase rootfs_data") + local result = {} + result["result"] = true + luci.http.write_json(result) + exec_cmd_in_sh("killall dropbear uhttpd; sleep 1; /sbin/router_reset;/sbin/reboot") +end + +function set_passwd() + local p1 = luci.http.formvalue("pwd1") + local p2 = luci.http.formvalue("pwd2") + local stat = nil + if p1 ~= nil and luci.sys.user.checkpasswd("root", p1) then + if p2 ~= nil then + stat = luci.sys.user.setpasswd("root", p2) + luci.http.status(200, "setpasswd successful!") + luci.http.write("setpasswd successful!") + return + end + end + luci.http.status(500, "Bad passwd!") + --luci.http.write("setpasswd failed!") +end + +function rts_get_access_token() + local dbfs = require "meizu.dbfs" + dbfs.init_access_token_table() + local dbdata = dbfs.fetch_access_token() + local token + if #dbdata > 0 then + for _, data in ipairs(dbdata) do + local tokenFromdb = data.token + local expireTimeFromdb = data.expireTime + local nowTime = os.time() + if expireTimeFromdb < nowTime then + require "MZLog".log(3, "expireTime expire") + local httpsData = https_get_access_token() + token = httpsData.access_token + dbfs.update_access_token(tokenFromdb, token, httpsData.expires_in + os.time() - 10) + else + require "MZLog".log(3, "token from db") + token = tokenFromdb + end + end + else + local httpsData = https_get_access_token() + token = httpsData.access_token + require "MZLog".log(3, "token from https") + dbfs.add_access_token(token, httpsData.expires_in + os.time() - 10) + end + return token +end + +function https_get_access_token() + local url = "https://api.meizu.com/oauth/token?scope=router_trust&device=" + local suffix = "&password=&grant_type=device_only&client_id=gkzyJzq4RPoaov3BamqsJgg&client_secret=yh9bdKurxxotCjrEvJOiumk2mrzhcyej" + local SN = get_device_SN() + url = url..SN..suffix + local res, code, headers, status = get_https_data(url) + local data = cjson.decode(res) + return data +end + +function get_user_access_token() + local res, code, headers, status + local url = 'https://api.meizu.com/oauth/token?grant_type=password&client_id=gkzyJzq4RPoaov3BamqsJgg&client_secret=yh9bdKurxxotCjrEvJOiumk2mrzhcyej&username=appadmin@flyme.cn&password=appadmin111&scope=router_trust' + local res, code, headers, status = get_https_data(url) + local data = cjson.decode(res) + return data.access_token +end + +function init_bind_router_body(access_token) + local body = "access_token=" + local uat = luci.http.formvalue("uat") + body = body..access_token + body = body.."&user_access_token=" + body = body..uat + return body +end + +function bind_router() + local url = "https://router.meizu.com/oauth/router/bindRouter" + local access_token = rts_get_access_token() + local body = init_bind_router_body(access_token) + local https = require("ssl.https") + local res, code, headers, status = https.request(url, body) + if code == 401 then + delete_access_token() + access_token = rts_get_access_token() + body = init_bind_router_body(access_token) + res, code, headers, status = https.request(url, body) + end + luci.http.write(res) +end + +function unbind_router() + local url = 'https://router.meizu.com/oauth/user/unbind?access_token=' + local https = require("ssl.https") + local uat = luci.http.formvalue("uat") + url = url..uat + url = url..'&device='..get_device_SN() + local res, code, headers, status = https.request(url) + luci.http.write(res) +end + +function get_device_SN() + local sn = "" + local fd = io.popen("nvram get sn") + if fd then + local ln = fd:read("*l") + if ln ~= nil then + sn = ln + end + fd:close() + end + return sn +end + +function get_device_version() + local device_version = "1.0.0" + --[[ + [local pcall, dofile = pcall, dofile + [if pcall(dofile, "/etc/openwrt_release") then + [ if DISTRIB_RELEASE ~= nil then + [ device_version = DISTRIB_RELEASE + [ end + [end + ]] + local lu = require("luci.util") + local cmd = [[cat /etc/openwrt_version|awk '{printf $1}']] + local v = lu.exec(cmd) + if v ~= nil then + device_version = v + end + return device_version +end + +function silent_upgrade() + local fd = nil + local image = "/tmp/firmware.img" + local touchcmd = "touch "..image + exec_cmd_in_sh(touchcmd) + local function image_supported() + return ( 0 == os.execute( + ". /lib/functions.sh; " .. + "include /lib/upgrade; " .. + "platform_check_image %q >/dev/null" + % image + )) + end + if luci.http.formvalue("act") == "update" then + luci.http.write("act == update") + end + if image_supported() then + luci.http.write("updating") + exec_cmd_in_sh("killall dropbear uhttpd; sleep 1; /sbin/sysupgrade -v %q" %{ image }) + luci.http.write("update finished!") + else + luci.http.write("image_supported check failed!") + end +end + +function batchfile_checklist() + local IMEI = luci.http.formvalue("imei") + local dbfs = require "meizu.dbfs" + local searchEndFlag = "searchend" + local flag = dbfs.fetchBatchFileEndFlag(searchEndFlag, IMEI) + dbfs.deleteBatchFileEndFlag(searchEndFlag, IMEI) + local res = dbfs.fetchAllBatchFile(IMEI) + local result = res + dbfs.deleteBatchFile(IMEI) + res = cjson.encode(res) + + if next(result) ~= nil then + if flag.hashCode ~= nil then + res = '{"status":"2002", "data":'..res.."}" + else + res = '{"status":"2001", "data":'..res.."}" + end + else + res = '{"status":"2003"}' + end + luci.http.write(res) + return res +end + +function findInDir(rootpath, wefind, hashCode, md5sum, IMEI) + local dbfs = require "meizu.dbfs" + local flag = 0 + local ret, files, iter = pcall(lfs.dir, rootpath) + if ret == false then + return nil + end + for entry in files, iter do + if entry ~= '.' and entry ~= '..' then + local f = rootpath .. '/' .. entry + local filename = string.match(f, ".+/([^/]*%.%w+)$") + + if wefind == filename then + flag = 1 + if(md5sum == luci.sys.exec("md5sum %q" % f):match("^([^%s]+)")) then + require "MZLog".log(3, debug.getinfo(1).currentline) + else + dbfs.addBatchFile(hashCode, IMEI) + end + end + end + end + return flag +end + +function batchfile_compare_upload() + local data = luci.http.formvalue("data") + local tableData = cjson.decode(data) + local dbfs = require "meizu.dbfs" + dbfs.initBatchFileTable() + local LuciUtil = require("luci.util") + local sharePath = "/mnt/Image" + local ID = nil + for key, value in pairs(tableData) do + local wefind = value.fileName + local md5sum = value.md5 + local hashCode = value.hashCode + local IMEI = value.imei + local rootpath = sharePath + ID = IMEI + + local ret, files, iter = pcall(lfs.dir, rootpath) + if ret == false then + dbfs.addBatchFile(hashCode, IMEI) + end + local flag = findInDir(rootpath, wefind, hashCode, md5sum, IMEI) + if flag == 0 then + dbfs.addBatchFile(hashCode, IMEI) + end + end + local searchEndFlag = "searchend" + dbfs.addBatchFile(searchEndFlag, ID) +end + +function table_merge(t1, t2) + if (type(t1) == "table") and (type(t2) == "table") then + for k, v in pairs(t2) do + if (type(v) == "table") and (type(t1[k] or false) == "table") then + table_merge(t1[k], t2[k]) + else + t1[k] = v + end + end + end + return t1 +end + +function get_files_list(path, start, count, ID) + local result = {} + local ret, files, iter = pcall(lfs.dir, path) + local cmd_file = "ls -al " .. '"'.. path ..'"'.. " | awk '/^-/' | wc -l" + local cmd_dir = "ls -al " .. '"'.. path ..'"'.. " | awk '/^d/' | wc -l" + local luaUtil = require"luci.util" + local file_num = luaUtil.exec(cmd_file) + local dir_num = luaUtil.exec(cmd_dir) + local total_num = file_num + dir_num - 2 + local start = tonumber(start) + local count = tonumber(count) + local fs = require "nixio.fs" + + if ret == true then + for file in lfs.dir(path) do + if file ~= "." and file ~= ".." then + local f = path..'/'..file + local fname = file + local attr = lfs.attributes(f) + assert (type(attr) == "table") + + if attr.mode == "directory" then + local res = {name = "", isfile = nil, size = nil, time = nil} + local cmd_file = "ls -al " .. '"'.. f ..'"'.. " | awk '/^-/' | wc -l" + local cmd_dir = "ls -al " .. '"'.. f ..'"'.. " | awk '/^d/' | wc -l" + local size_file = luaUtil.exec(cmd_file) + local size_dir = luaUtil.exec(cmd_dir) + local size = size_file + size_dir - 2 + local name = fname + local stat = fs.stat(f) + local time = stat.mtime + res.name = fname + res.isfile = 0 + res.size = size + res.time = time + + table.insert(result, res) + else + local res = {name = "", isfile = nil, size = nil, time = nil} + local name = fname + local stat = fs.stat(f) + local time = stat.mtime + local size = nixio.fs.stat(f).size + res.name = fname + res.isfile = 1 + res.size = size + res.time = time + + table.insert(result, res) + end + end + end + if total_num > count then + total_num = count + end + + table.sort(result, function(a, b) return (a.isfile < b.isfile) end) + local res = {} + for i = start + 1, start + count do + table.insert(res, result[i]) + end + + local res = cjson.encode(res) + path = string.gsub(path, "mnt", "router") + res = '{"result":true, "start":'..start..', "count":'..total_num..', "path":"'..path..'", "fileinfo":'..res.."}" + luci.http.write(res) + return res + end +end + +function getFilesList() + local path = luci.http.formvalue("path") + local start = luci.http.formvalue("start") + local count = luci.http.formvalue("count") + local ID = luci.http.formvalue("ID") + local result = get_files_list(path, start, count, ID) + --luci.http.write(result) + return result +end + +function sysinfo() + local lue = require("luci.util").exec + local ret = {} + ret["romversion"] = get_device_version() + ret["SN"] = get_device_SN() + ret["deviceModel"] = "R10" + ret["routername"] = "mzrt"..get_device_SN() + local ssid1, ssid2 = require "meizu.nwfs".get_wifi_ssids() + ret["ssid1"] = ssid1 + ret["ssid2"] = ssid2 + local cmd = [[df /mnt|grep -q sda;echo -n $?]] + ret["diskstatus"] = lue(cmd) + return ret +end diff --git a/Me_Lua/h10/meizu/btfs.lua b/Me_Lua/h10/meizu/btfs.lua new file mode 100644 index 0000000..4c16467 --- /dev/null +++ b/Me_Lua/h10/meizu/btfs.lua @@ -0,0 +1,1442 @@ +module("meizu.btfs", package.seeall) +--network functions + +local cjson = require "cjson" +local lfs = require "lfs" +local bfs = require "meizu.bfs" +local RC = require "meizu.r10config" +local dbfs = require("meizu.dbfs") +local posix = require("Posix") + +local bind_router = bfs.bind_router +local data_to_json = bfs.data_to_json +local exec_cmd_in_sh = bfs.exec_cmd_in_sh +local exec_reboot = bfs.exec_reboot +local get_device_SN = bfs.get_device_SN +local get_device_version = bfs.get_device_version +local get_https_data = bfs.get_https_data +local rts_get_access_token = bfs.rts_get_access_token +local set_passwd = bfs.set_passwd +local silent_upgrade = bfs.silent_upgrade +local strsplit = bfs.strsplit +local b64dec = bfs.b64dec +local b64enc = bfs.b64enc + +local lue = require("luci.util").exec + +------------------------ bluetooth -------------------- + +----------------------- receive data -------------------- +function bluetooth_info() + dbfs.initBluetoothTable() + local value = luci.http.formvalue("data") + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, value) + local ret = {} + local types = string.sub(value, 1, 2) + + if types == "00" then + local id = string.sub(value, 3, 4) + local status = string.format("%d", "0x" .. string.sub(value, 5, 6)) + local temp1 = string.sub(value, 7, 8) + local temp2 = string.sub(value, 9, 10) + local temp = temp2..temp1 + temp = string.format("%d", "0x" .. temp) + local rh1 = string.sub(value, 11, 12) + local rh2 = string.sub(value, 13, 14) + local rh = rh2..rh1 + rh = string.format("%d", "0x" .. rh) + local light1 = string.sub(value, 15, 16) + local light2 = string.sub(value, 17, 18) + local light = light2..light1 + light = string.format("%d", "0x" .. light) + local mac = dbfs.getBluetoothDevice(id) + local TMP = "/tmp/"..mac.."0" + + ret["mac"] = mac + ret["id"] = id + if status == "1" then + ret["onoff"] = "on" + else + ret["onoff"] = "off" + end + local timer_id = "" + local flag = "" + local start = "" + local ends = "" + local fd = io.open(TMP, "r") + + if fd then + local res = fd:read() + fd:close() + res = cjson.decode(res) + timer_id = res.timerId + flag = res.flag + start = res.start + ends = res.ends + end + + ret["timerId"] = timer_id + ret["flag"] = flag + ret["start"] = start + ret["ends"] = ends + ret["temp"] = temp + ret["hemi"] = rh + ret["light"] = light + ret["time"] = os.time() + + local result = data_to_json(ret) + --[[ + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, id) + require "MZLog".log(3, result) + require "MZLog".log(3, ret) + ]] + local fd = assert(io.open(TMP, "w")) + fd:write(result) + fd:close() + + elseif types == "01" then + local id = string.sub(value, 3, 4) + local voltage1 = string.sub(value, 5, 6) + local voltage2 = string.sub(value, 7, 8) + local voltage = voltage2..voltage1 + voltage = string.format("%d", "0x" .. voltage) + local electricity1 = string.format("%d", "0x" .. string.sub(value, 9, 10)) + local electricity2 = string.format("%d", "0x" .. string.sub(value, 11, 12)) + local electricity = electricity2..electricity1 + electricity = string.format("%d", "0x" .. electricity) + local power1 = string.sub(value, 13, 14) + local power2 = string.sub(value, 15, 16) + local power = power2..power1 + power = string.format("%d", "0x" .. power) + local electric1 = string.sub(value, 17, 18) + local electric2 = string.sub(value, 19, 20) + local electric = electric2..electric1 + electric = string.format("%d", "0x" .. electric) + local mac = dbfs.getBluetoothDevice(id) + local TMP = "/tmp/"..mac.."1" + local timer_id = "" + local fd = io.open(TMP, "r") + if fd then + local res = fd:read() + fd:close() + res = cjson.decode(res) + timer_id = res.timerId + end + + ret["timerId"] = timer_id + ret["mac"] = mac + ret["id"] = id + ret["voltage"] = voltage + ret["current"] = electricity + ret["power"] = power + ret["energy"] = electric + + local result = data_to_json(ret) + local fd = assert(io.open(TMP, "w")) + fd:write(result) + fd:close() + + elseif types == "02" then + require "MZLog".log(3, debug.getinfo(1).currentline) + local id = string.sub(value, 3, 4) + local TYPE = string.sub(value, 5, 6) + local mac1 = string.sub(value, 7, 8) + local mac2 = string.sub(value, 9, 10) + local mac3 = string.sub(value, 11, 12) + local mac4 = string.sub(value, 13, 14) + local mac5 = string.sub(value, 15, 16) + local mac6 = string.sub(value, 17, 18) + local mac = mac6..mac5..mac4..mac3..mac2..mac1 + + mac = string.upper(mac) + local ID = "" + local res = dbfs.fetchBluetoothDevice(mac) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, #res) + require "MZLog".log(3, res) + if #res > 0 then + for k, v in pairs(res) do + ID = v.id + end + end + if id ~= ID then + dbfs.updateBluetoothDevice(id, "", "", "", mac) + end + local TMP = "/tmp/"..mac.."0" + local fd = io.open(TMP, "r") + + if fd then + local res = fd:read() + fd:close() + res = cjson.decode(res) + res["time"] = os.time() + res = cjson.encode(res) + local fd = io.open(TMP, "w") + fd:write(res) + fd:close() + end + require "MZLog".log(3, id) + require "MZLog".log(3, mac) + require "MZLog".log(3, debug.getinfo(1).currentline) + + elseif types == "09" then + local deviceType = string.sub(value, 3, 4) + local mac1 = string.sub(value, 5, 6) + local mac2 = string.sub(value, 7, 8) + local mac3 = string.sub(value, 9, 10) + local mac4 = string.sub(value, 11, 12) + local mac5 = string.sub(value, 13, 14) + local mac6 = string.sub(value, 15, 16) + local mac = mac6..mac5..mac4..mac3..mac2..mac1 + mac = string.upper(mac) + + local res = dbfs.fetchBluetoothDevice(mac) + local ret = nil + local id = nil + if #res > 0 then + for k, v in pairs(res) do + ret = v.mac + id = v.id + end + end + if id then + dbfs.updateBluetoothDevice("", "", "", "", mac) + end + if ret == nil then + dbfs.addBluetoothDevice("", mac, "", "", deviceType, "") + local TMP = "/tmp/"..mac + local fd = io.open(TMP, "w") + fd:write(os.time()) + fd:close() + else + local TMP = "/tmp/"..mac + local fd = io.open(TMP, "w") + fd:write(os.time()) + fd:close() + end + + elseif types == "04" then + local data = string.format("%d", "0x" .. string.sub(value, 3, 4)) + ret["data"] = data + + elseif types == "03" then + require "MZLog".log(3, debug.getinfo(1).currentline) + local id = string.sub(value, 3, 4) + local flag = string.sub(value, 5, 6) + local timer_id = string.sub(value, 7, 8) + local start = string.sub(value, 9, 16) + local ends = string.sub(value, 17, 24) + local mac = dbfs.getBluetoothDevice(id) + local TMP = "/tmp/"..mac.."1" + local fd = io.open(TMP, "r") + + if fd then + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, timer_id) + require "MZLog".log(3, flag) + local res = fd:read() + res = cjson.decode(res) + if timer_id == res["timerId"] then + local TMP = "/tmp/"..mac.."0" + local fd = io.open(TMP, "r") + local res = fd:read() + res = cjson.decode(res) + res["flag"] = flag + res["timerId"] = timer_id + res["start"] = start + res["ends"] = ends + res = cjson.encode(res) + local fd = io.open(TMP, "w") + fd:write(res) + fd:close() + end + end + + elseif types == "06" then + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + local id = string.sub(value, 3, 4) + local mac = dbfs.getBluetoothDevice(id) + local len = tonumber(dbfs.getBleDeviceNameLength(id)) + local str = string.sub(value, 5, len + 4) + --local res = {} + --[[ + for i = 1, #str, 2 do + res[#res + 1] = (tonumber(string.format("%d", "0x"..string.sub(str, i, i+1)))) + end + ]] + local device_name = str + --[[ + if #res == 1 then + device_name = string.char(res[1]) + elseif #res == 2 then + device_name = string.char(res[1], res[2]) + elseif #res == 3 then + device_name = string.char(res[1], res[2], res[3]) + elseif #res == 4 then + device_name = string.char(res[1], res[2], res[3], res[4]) + elseif #res == 5 then + device_name = string.char(res[1], res[2], res[3], res[4], res[5]) + elseif #res == 6 then + device_name = string.char(res[1], res[2], res[3], res[4], res[5], res[6]) + elseif #res == 7 then + device_name = string.char(res[1], res[2], res[3], res[4], res[5], res[6], res[7]) + elseif #res == 8 then + device_name = string.char(res[1], res[2], res[3], res[4], res[5], res[6], res[7], res[8]) + elseif #res == 9 then + device_name = string.char(res[1], res[2], res[3], res[4], res[5], res[6], res[7], res[8], res[9]) + elseif #res == 10 then + device_name = string.char(res[1], res[2], res[3], res[4], res[5], res[6], res[7], res[8], res[9], res[10]) + end + ]] + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, str) + require "MZLog".log(3, device_name) + dbfs.updateBluetoothDevice(id, "", device_name, len, mac) + require "MZLog".log(3, debug.getinfo(1).currentline) + + elseif types == "07" then + local data = string.format("%d", "0x" .. string.sub(value, 3, 4)) + ret["data"] = data + + elseif types == "0b" then + local key_ack = string.sub(value, 3, 4) + local TMP = "/tmp/0b0b" + local fd = io.open(TMP, "w") + fd:write(key_ack) + fd:close() + + elseif types == "0c" then + local id = string.sub(value, 3, 4) + local status = string.sub(value, 5, 6) + local mac = dbfs.getBluetoothDevice(id) + local TMP = "/tmp/"..mac.."0" + local fd = io.open(TMP, "r") + local res = nil + require "MZLog".log(3, debug.getinfo(1).currentline) + + if fd then + res = fd:read() + fd:close() + res = cjson.decode(res) + if status == "01" then + res["onoff"] = "on" + else + res["onoff"] = "off" + end + res = cjson.encode(res) + local fd = io.open(TMP, "w") + fd:write(res) + fd:close() + end + require "MZLog".log(3, res) + + elseif types == "0d" then + local id = string.sub(value, 3, 4) + local led_light = string.sub(value, 5, 6) + local temp1 = string.sub(value, 7, 8) + local temp2 = string.sub(value, 9, 10) + led_light = string.format("%d", "0x" .. led_light) + local led_temp = temp2..temp1 + temp = string.format("%d", "0x" .. temp) + + local TMP = "/tmp/"..mac.."0" + local fd = io.open(TMP, "r") + local res = nil + require "MZLog".log(3, debug.getinfo(1).currentline) + + if fd then + res = fd:read() + fd:close() + res = cjson.decode(res) + res["led_light"] = led_light + res["led_temp"] = led_temp + + res = cjson.encode(res) + local fd = io.open(TMP, "w") + fd:write(res) + fd:close() + end + + elseif types == "0e" then + local id = string.sub(value, 3, 4) + local wait_time = string.format("%d", "0x" .. string.sub(value, 5, 6)) + --local mac = dbfs.getBluetoothDevice(id) + local TMP = "/tmp/0e0e" + local fd = io.open(TMP, "w") + fd:write(wait_time) + fd:close() + + elseif types == "10" then + local mac1 = string.sub(value, 3, 4) + local mac2 = string.sub(value, 5, 6) + local mac3 = string.sub(value, 7, 8) + local mac4 = string.sub(value, 9, 10) + local mac5 = string.sub(value, 11, 12) + local mac6 = string.sub(value, 13, 14) + local mac = mac6..mac5..mac4..mac3..mac2..mac1 + mac = string.upper(mac) + + local res = dbfs.fetchBluetoothDevice(mac) + if #res == 0 then + dbfs.addBluetoothDevice("", mac, "0123", "", "", "") + end + --[[ + if ret == nil then + dbfs.addBluetoothDevice("", mac, "", "", deviceType, "") + local TMP = "/tmp/"..mac + local fd = io.open(TMP, "w") + fd:write(os.time()) + fd:close() + else + local TMP = "/tmp/"..mac + local fd = io.open(TMP, "w") + ]] + end + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, ret) + return ret +end + +function nw_get_bluetooth_info() + require "MZLog".log(3, debug.getinfo(1).currentline) + local res = bluetooth_info() + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_get_bluetooth_info() + require "MZLog".log(3, debug.getinfo(1).currentline) + local res = bluetooth_info() + require "MZLog".log(3, debug.getinfo(1).currentline) + return res +end + +----------------------- scan_ble_device -------------------- +function scan_ble_switch(status) + local res = {} + if status == "on" then + local cmd = "bt_daemon -s ".."16".." 255" + lue(cmd) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, cmd) + posix.sleep(1) + res["result"] = true + elseif status == "off" then + local cmd = "bt_daemon -s ".."18".." 255" + lue(cmd) + posix.sleep(1) + res["result"] = false + end + return res +end + +function nw_scan_ble_switch() + local status = luci.http.formvalue("status") + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, status) + local res = scan_ble_switch(status) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_scan_ble_switch(status) + local res = scan_ble_switch(status) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + return cjson.encode(res) +end + +----------------------- get_ble_device_list -------------------- +function get_ble_device_list() + local res = dbfs.fetchAllBluetoothDevice() + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, res) + local result = {} + if #res > 0 then + for k, v in pairs(res) do + local TMP = "/tmp/"..v.mac + local fd = io.open(TMP, "r") + if fd then + local time = fd:read() + fd:close() + if tonumber(os.time()) - tonumber(time) < 5 then + table.insert(result, v) + end + end + end + end + return result +end + +function nw_get_ble_device_list() + local res = get_ble_device_list() + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + if #res == 0 then + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write("[]") + else + luci.http.write_json(res) + end +end + +function ww_get_ble_device_list() + local res = get_ble_device_list() + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + if #res == 0 then + return "[]" + else + return cjson.encode(res) + end +end + +----------------------- add_ble_mesh_device -------------------- +function is_receive_id(mac) + local id = "" + local ret = dbfs.fetchBluetoothDevice(mac) + for k, v in pairs(ret) do + id = v.id + end + return id +end + +function add_ble_mesh_device(mac) + local res = {} + local id = "" + local mac1 = string.format("%d", "0x" .. string.sub(mac, 1, 2)) + local mac2 = string.format("%d", "0x" .. string.sub(mac, 3, 4)) + local mac3 = string.format("%d", "0x" .. string.sub(mac, 5, 6)) + local mac4 = string.format("%d", "0x" .. string.sub(mac, 7, 8)) + local mac5 = string.format("%d", "0x" .. string.sub(mac, 9, 10)) + local mac6 = string.format("%d", "0x" .. string.sub(mac, 11, 12)) + local macs = mac6.." "..mac5.." "..mac4.." "..mac3.." "..mac2.." "..mac1 + + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, mac) + local cmd = "bt_daemon -s ".."17 "..macs + lue(cmd) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, cmd) + + for i = 1, 20 do + posix.sleep(1) + id = is_receive_id(mac) + if id ~= "" then + break + end + end + if id ~= "" then + res["result"] = true + res["id"] = id + res["mac"] = mac + else + res["result"] = false + res["mac"] = mac + end + return res +end + +function nw_add_ble_mesh_device() + local mac = luci.http.formvalue("mac") + local res = add_ble_mesh_device(mac) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_add_ble_mesh_device(mac) + local res = add_ble_mesh_device(mac) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + return cjson.encode(res) +end + +----------------------- get_ble_device_detail -------------------- +function get_ble_device_status(mac) + local TMP1 = "/tmp/"..mac.."0" + local TMP2 = "/tmp/"..mac.."1" + local fd1 = io.open(TMP1, "r") + local fd2 = io.open(TMP2, "r") + if fd1 and fd2 then + local res1 = fd1:read() + local res2 = fd2:read() + fd1:close() + fd2:close() + --require "MZLog".log(3, res1) + --require "MZLog".log(3, res2) + if res1 ~= nil and res2 ~= nil then + res1 = cjson.decode(res1) + res2 = cjson.decode(res2) + res1["voltage"] = res2.voltage + res1["current"] = res2.current + res1["power"] = res2.power + res1["energy"] = res2.energy + + local ret = dbfs.fetchBluetoothDevice(mac) + local deviceType = nil + local name = nil + for k, v in pairs(ret) do + deviceType = v.deviceType + name = v.name + end + + res1["name"] = name + res1["type"] = deviceType + res1["time"] = nil + --require "MZLog".log(3, res1) + require "MZLog".log(3, debug.getinfo(1).currentline) + end + if res1 == "" then + res1 = "{}" + end + return res1 + else + return "{}" + end +end + +function nw_get_ble_device_status() + local mac = luci.http.formvalue("mac") + local res = get_ble_device_status(mac) + --require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + if res == "{}" then + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, res) + luci.http.write(res) + else + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, res) + luci.http.write_json(res) + end +end + +function ww_get_ble_device_status(mac) + local res = get_ble_device_status(mac) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + if res == "{}" then + return res + else + return cjson.encode(res) + end +end + +----------------------- remove_ble_from_mesh -------------------- +function is_remove_ble_from_mesh() + local res = nil + local TMP = "/tmp/0e0e" + local fd = io.open(TMP, "r") + if fd then + local ret = fd:read() + fd:close() + if ret ~= "" and ret ~= nil then + return ret + else + return nil + end + else + return nil + end +end + +function remove_ble_from_mesh(mac) + local res = {} + local ret = dbfs.fetchBluetoothDevice(mac) + local id = nil + for k, v in pairs(ret) do + id = v.id + end + if id ~= nil and id ~= "" then + local cmd = "bt_daemon -s ".."3 "..string.format("%d", "0x"..id) + lue(cmd) + local wait_time = nil + for i = 1, 20 do + posix.sleep(1) + wait_time = is_remove_ble_from_mesh(mac) + if wait_time ~= nil then + break + end + end + if wait_time then + res["result"] = true + res["waitTime"] = wait_time + res["mac"] = mac + res["id"] =id + else + res["result"] = false + res["mac"] = mac + res["id"] = id + end + else + res["result"] = false + res["mac"] = mac + end + return res +end + +function nw_remove_ble_from_mesh() + local mac = luci.http.formvalue("mac") + local res = remove_ble_from_mesh(mac) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_remove_ble_from_mesh(mac) + local res = remove_ble_from_mesh(mac) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + return cjson.encode(res) +end + +----------------------- get_mesh_device_list -------------------- +function is_file_exist(TMP) + local fd = io.open(TMP, "r") + if fd then + return fd + else + require "MZLog".log(3, debug.getinfo(1).currentline) + return false + end +end + +function get_mesh_device_list() + local result = {} + local ret = dbfs.fetchAllBleMeshDevice() + if #ret > 0 then + for k, v in pairs(ret) do + local res = {} + local TMP = "/tmp/" .. v.mac .."0" + local fd = nil + fd = is_file_exist(TMP) + --[[ + for i = 1, 5 do + fd = is_file_exist(TMP) + if fd then + break + else + posix.sleep(1) + end + end + ]] + if fd then + local value = fd:read() + if value ~= nil then + value = cjson.decode(value) + end + res["mac"] = v.mac + --res["online"] = true + res["name"] = v.name + res["type"] = v.deviceType + if value["onoff"] == "on" then + res["onoff"] = "on" + else + res["onoff"] = "off" + end + + if tonumber(os.time()) - tonumber(value.time) > 60 then + res["online"] = false + else + res["online"] = true + end + + if res["online"] == false then + res = nil + end + table.insert(result, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + + else + res["mac"] = v.mac + res["name"] = v.name + res["type"] = v.deviceType + res["onoff"] = "off" + res["online"] = false + table.insert(result, res) + require "MZLog".log (3, debug.getinfo(1).currentline) + end + end + end + return result +end + +function nw_get_mesh_device_list() + local res = get_mesh_device_list() + --require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + if #res == 0 then + luci.http.write("[]") + else + luci.http.write_json(res) + end +end + +function ww_get_mesh_device_list() + local res = get_mesh_device_list() + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + if #res == 0 then + return "[]" + else + return cjson.encode(res) + end +end + +----------------------- dismiss_mesh -------------------- +function dismiss_mesh() + local res = {} + local cmd = "bt_daemon -s ".."3 ".." 255" + lue(cmd) + res["result"] = true +end +function nw_dismiss_mesh() + local res = dismiss_mesh() + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +----------------------- set_mesh_device_attr -------------------- +function is_switch_on(mac) + local TMP = "/tmp/"..mac.."0" + local fd = io.open(TMP, "r") + if fd then + local res = fd:read() + fd:close() + res = cjson.decode(res) + if res["onoff"] == "on" then + return true + else + return nil + end + end +end + +function is_switch_off(mac) + local TMP = "/tmp/"..mac.."0" + local fd = io.open(TMP, "r") + if fd then + local res = fd:read() + fd:close() + res = cjson.decode(res) + if res["onoff"] == "off" then + return true + else + return nil + end + end +end + +function is_set_name_ok(mac) + local name = "" + local ret = dbfs.fetchBluetoothDevice(mac) + for k, v in pairs(ret) do + name = v.name + end + return name +end + +function set_mesh_device_attr(mac, key, value) + local res = {} + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, mac) + require "MZLog".log(3, key) + require "MZLog".log(3, value) + + local fd = io.open("/tmp/meshDeviceFlag", "r") + if fd then + local time = tonumber(fd:read()) + if os.time() - time < 50 then + local res = {} + res["result"] = true + return res + end + end + + local ret = dbfs.fetchBluetoothDevice(mac) + local id = nil + if #ret > 0 then + for k, v in pairs(ret) do + id = v.id + end + end + --[[ + local fd1 = io.open("/tmp/tmp", "a") + fd1:write(key) + fd1:write(value) + ]] + + + if id ~= nil then + --local cmd = "touch /tmp/flag" + --lue(cmd) + local fd = io.open("/tmp/meshDeviceFlag", "w") + fd:write(os.time()) + fd:close() + + if key == "8" and value == "true" then + local cmd = "bt_daemon -s ".."1 "..string.format("%d", "0x"..id).." 1" + lue(cmd) + local flag = nil + for i = 1, 10 do + flag = is_switch_on(mac) + if flag then + break + else + posix.sleep(1) + end + end + if flag then + res["result"] = true + res["mac"] = mac + res["key"] = key + res["onoff"] = " on" + else + res["result"] = false + res["mac"] = mac + res["key"] = key + res["onoff"] = "off" + end + + elseif key == "8" and value == "false" then + local cmd = "bt_daemon -s ".."1 "..string.format("%d", "0x"..id).." 0" + lue(cmd) + local flag = nil + for i = 1, 10 do + flag = is_switch_off(mac) + if flag then + break + else + posix.sleep(1) + end + end + if flag then + res["result"] = true + res["mac"] = mac + res["key"] = key + res[ "onoff"] = "off" + else + res[ "result"] = false + res["mac"] = mac + res["key"] = key + res["onoff"] = "on" + end + + elseif key == "0" then + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, value) + if #value > 20 then + value = string.sub(value, 1, 20) + end + require "MZLog".log(3, debug.getinfo(1).currentline) + local name = "" + for i = 1, #value, 2 do + name = name.." "..string.format("%d", "0x"..string.sub(value, i, i+1)) + end + + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, name) + local len = #value + if len > 20 then + len = 20 + end + require "MZLog".log(3, len) + dbfs.updateBluetoothDevice(id, "", "", len, mac) + require "MZLog".log(3, debug.getinfo(1).currentline) + local cmd = "bt_daemon -s ".."13 "..string.format("%d", "0x"..id).." "..name + lue(cmd) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, cmd) + + local name = "" + for i = 1, 10 do + posix.sleep(1) + name = is_set_name_ok(mac) + if name ~= "" then + break + end + end + + if name ~= "" and name ~= nil then + res ["result"] = true + res["mac"] = mac + res["key"] = key + else + res[ "result"] = false + res["mac"] = mac + res["key"] = key + end + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + end + else + res["result"] = false + res["mac"] = mac + res["key"] = key + end + --[[ + fd1:write(cjson.encode(res)) + fd1:write("\n") + fd1:close() + ]] + return res +end + +function nw_set_mesh_device_attr() + local mac = luci.http.formvalue("mac") + local key = luci.http.formvalue("key") + local value = luci.http.formvalue("value") + local res = set_mesh_device_attr(mac, key, value) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + local cmd = "rm /tmp/meshDeviceFlag" + lue(cmd) + + luci.http.write_json(res) +end + +function ww_set_mesh_device_attr(mac, key, value) + local res = set_mesh_device_attr(mac, key, value) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + local cmd = "rm /tmp/meshDeviceFlag" + lue(cmd) + return cjson.encode(res) +end + +----------------------- reboot_mesh_device -------------------- +function reboot_mesh_device(mac) + local res = {} + local ret = dbfs.fetchBluetoothDevice(mac) + local id = nil + for k, v in pairs(ret) do + id = v.id + end + + local cmd = "bt_daemon -s ".."4 "..string.format("%d", "0x"..id) + lue(cmd) + posix.sleep(2) + res["result"] = true +end + +function nw_reboot_mesh_device() + local mac = luci.http.formvalue("mac") + local res = reboot_mesh_device(mac) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_reboot_mesh_device(mac) + local res = reboot_mesh_device(mac) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + return cjson.encode(res) +end + +----------------------- unmesh_all_device -------------------- +function unmesh_all_device() + local res = {} + local cmd = "bt_daemon -s ".."3 ".."255" + lue(cmd) + require "MZLog".log(3, debug.getinfo(1).currentline) + local wait_time = nil + for i = 1, 20 do + wait_time = is_remove_ble_from_mesh() + if wait_time ~= nil then + break + else + posix.sleep(1) + end + end + if wait_time then + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + res["result"] = true + else + res["result"] = false + end + require "MZLog".log(3, debug.getinfo(1).currentline) + return res +end + +function nw_unmesh_all_device() + local res = unmesh_all_device() + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_unmesh_all_device() + local res = unmesh_all_device() + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + return cjson.encode(res) +end + +----------------------- set_mesh_device_timer -------------------- +function is_set_timer_ok(mac, timer_id) + local TMP = "/tmp/"..mac.."0" + local fd = io.open(TMP, "r") + if fd then + local ret = fd:read() + ret = cjson.decode(ret) + fd:close() + if ret["timerId"] == timer_id then + return true + else + return nil + end + else + return nil + end +end +function set_mesh_device_timer(mac, timer_id, flag, start_time, end_time) + local res = {} + local ret = dbfs.fetchBluetoothDevice(mac) + local id = nil + for k ,v in pairs(ret) do + id = v.id + end + local ret = dbfs.getBleTimerId(id, timer_id) + if ret == "" then + dbfs.addBleTimer(id, timer_id, flag, start_time, end_time) + end + --[[ + local start = start + local ends = ends + if string.len(start) == 6 then + start = "00"..start + elseif string.len(start) == 5 then + start = "000"..start + elseif string.len(start) == 4 then + start = "0000"..start + end + + if string.len(ends) == 6 then + ends = "00"..ends + elseif string.len(ends) == 5 then + ends = "000"..ends + elseif string.len(ends) == 4 then + ends = "0000"..ends + end + require "MZLog".log(3, mac) + require "MZLog".log(3, timer_id) + require "MZLog".log(3, flag) + require "MZLog".log(3, start) + require "MZLog".log(3, ends) + + local TMP = "/tmp/"..mac.."1" + local fd = io.open(TMP, "r") + if fd then + local res = fd:read() + res = cjson.decode(res) + res["timerId"] = timer_id + res = cjson.encode(res) + local fd = io.open(TMP, "w") + fd:write(res) + fd:close() + end + + local start1 = string.sub(start, 1, 2) + local start2 = string.sub(start, 3, 4) + local start3 = string.sub(start, 5, 6) + local start4 = string.sub(start, 7, 8) + local end1 = string.sub(ends, 1, 2) + local end2 = string.sub(ends, 3, 4) + local end3 = string.sub(ends, 5, 6) + local end4 = string.sub(ends, 7, 8) + if id then + local start = string.format("%d", "0x"..start1).." ".. + string.format("%d", "0x"..start2).." ".. + string.format("%d", "0x"..start3).." ".. + string.format("%d", "0x"..start4) + local ends = string.format("%d", "0x"..end1).." ".. + string.format("%d", "0x"..end2).." ".. + string.format("%d", "0x"..end3).." ".. + string.format("%d", "0x"..end4) + + local cmd = "/root/spi_send ".."6 "..string.format("%d", "0x"..id).. + " "..string.format("%d", "0x"..flag).." ".. + string.format("%d", "0x"..timer_id).." "..start.." "..ends + require "MZLog".log(3, cmd) + lue(cmd) + + local times = tonumber(os.time()) - 1420041600 + local res = string.format("%x", times) + local time = "" + for i = 1, #res, 2 do + time = time.." "..string.format("%d", "0x"..string.sub(res, i, i+1)) + end + local cmd = "/root/spi_send ".."7 "..string.format("%d", "0x"..id).." "..time + lue(cmd) + end + + local flag = nil + for i = 1, 10 do + posix.sleep(1) + flag = is_set_timer_ok(mac, timer_id) + if flag then + break + end + end + if flag then + res["result"] = true + res["mac"] = mac + res["timerId"] = timer_id + else + res["result"] = false + res["mac"] = mac + res["timerId"] = timer_id + end + return res + ]] +end + +function nw_set_mesh_device_timer() + local mac = luci.http.formvalue("mac") + local timer_id = luci.http.formvalue("timerId") + local flag = luci.http.formvalue("flag") + local start_time = luci.http.formvalue("start") + local end_time = luci.http.formvalue("ends") + local timer = luci.http.formvalue("timer") + local res = set_mesh_device_timer(mac, timer_id, flag, start_time, end_time) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_set_mesh_device_timer(mac, timer_id, flag, start, ends) + local res = set_mesh_device_timer(mac, timer_id, flag, start, ends) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + return cjson.encode(res) +end + +----------------------- del_mesh_device_timer -------------------- +function is_del_timer_ok(mac, timer_id) + local TMP = "/tmp/"..mac.."0" + local fd = io.open(TMP, r) + if fd then + local ret = fd:read() + ret = cjson.decode(ret) + fd:close() + if ret["timerId"] ~= timer_id then + return true + else + return nil + end + else + return nil + end +end + +function del_mesh_device_timer(mac, timer_id) + local res = {} + local ret = dbfs.fetchBluetoothDevice(mac) + local id = nil + for k ,v in pairs(ret) do + id = v.id + end + local ret = dbfs.getBleTimerId(id, timer_id) + if ret ~= "" then + dbfs.deleteBleTimer(id, timer_id) + end + + --[[ + local cmd = "/root/spi_send ".."10 "..string.format("%d", "0x"..id).. + " "..string.format("%d", "0x"..timer_id) + lue(cmd) + local flag = nil + for i = 1, 10 do + posix.sleep(1) + flag = is_del_timer_ok(mac, timer_id) + if flag then + break + end + end + if flag then + res["result"] = true + res["mac"] = mac + res["timerId"] = timer_id + else + res["result"] = false + res["mac"] = mac + res["timerId"] = timer_id + end + return res + ]] +end + +function nw_del_mesh_device_timer() + local mac = luci.http.formvalue("mac") + local timer_id = luci.http.formvalue("timerId") + local res = del_mesh_device_timer(mac, timer_id) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_del_mesh_device_timer(mac, timer_id) + local res = del_mesh_device_timer(mac, timer_id) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + return cjson.encode(res) +end + +----------------------- set_encry_info -------------------- +function is_set_key_ok() + local TMP = "/tmp/0b0b" + local fd = io.open(TMP, "r") + require "MZLog".log(3, debug.getinfo(1).currentline) + if fd then + local file = fd:read() + fd:close() + if file == "00" then + local cmd = "rm /tmp/0b0b" + lue(cmd) + return true + elseif file == "01" then + return false + end + end +end + +function get_ble_device_key() + local ret = dbfs.fetchBluetoothDeviceKey() + if #ret > 0 then + return ret + else + return nil + end +end + +function set_mesh_network_pwd(old_key, new_key) + --local TMP = "/tmp/"..new_key + --local fd = io.open(TMP, "w") + --fd:write(new_key) + --fd:close() + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, old_key) + local key = new_key + require "MZLog".log(3, new_key) + local cmd = "bt_daemon -s 21" + lue(cmd) + local ret = nil + for i = 1, 10 do + ret = get_ble_device_key() + if ret then + break + else + posix.sleep(1) + end + end + + if #ret > 0 then + for k, v in pairs(ret) do + if v.key ~= old_key then + old_key = v.key + end + end + end + + local res = {} + require "MZLog".log(3, old_key) + require "MZLog".log(3, new_key) + local old_key1 = string.sub(old_key, 1, 1) + local old_key2 = string.sub(old_key, 2, 2) + local old_key3 = string.sub(old_key, 3, 3) + local old_key4 = string.sub(old_key, 4, 4) + local new_key1 = string.sub(new_key, 1, 1) + local new_key2 = string.sub(new_key, 2, 2) + local new_key3 = string.sub(new_key, 3, 3) + local new_key4 = string.sub(new_key, 4, 4) + require "MZLog".log(3, old_key1) + require "MZLog".log(3, old_key2) + require "MZLog".log(3, old_key3) + require "MZLog".log(3, old_key4) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + + --bt_daemon -s 21 + + local old_key = old_key1.." "..old_key2.." "..old_key3.." "..old_key4 + local new_key = new_key1.." "..new_key2.." "..new_key3.." "..new_key4 + local cmd = "bt_daemon -s ".."9 "..old_key.." "..new_key + lue(cmd) + require "MZLog".log(3, cmd) + local flag = nil + for i = 1, 10 do + flag = is_set_key_ok() + if flag ~= nil then + break + else + posix.sleep(1) + end + end + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, ret) + if flag then + if #ret > 0 then + for k, v in pairs(ret) do + local mac = v.mac + dbfs.updateBluetoothDevice("", key, "", "", mac) + end + end + end + + if flag then + res["result"] = true + res["newKey"] = key + else + res["result"] = false + res["newKey"] = key + end + return res +end + +function nw_set_mesh_network_pwd() + local old_key = luci.http.formvalue("oldKey") + local new_key = luci.http.formvalue("newKey") + local res = set_mesh_network_pwd(old_key, new_key) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_set_mesh_network_pwd (old_key, new_key) + local res = set_mesh_network_pwd(old_key, new_key) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + return cjson.encode(res) +end + +function set_lamp_brightness() + +end + +function nw_set_lamp_brightness() + local res = set_lamp_brightness() + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +function ww_set_lamp_brightness() + local res = set_lamp_brightness() + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + luci.http.write_json(res) +end + +------------------------ bluetooth -------------------- diff --git a/Me_Lua/h10/meizu/dbfs.lua b/Me_Lua/h10/meizu/dbfs.lua new file mode 100644 index 0000000..2629b16 --- /dev/null +++ b/Me_Lua/h10/meizu/dbfs.lua @@ -0,0 +1,604 @@ +module ("meizu.dbfs", package.seeall) + +local sqlite3 = require("lsqlite3") +local r10db = "/etc/r10db" + +function database_busy() + return true +end + +function updateDeviceNickname(mac, nickname) + local db = sqlite3.open(r10db) + local sqlStr = string.format("update maclist set devicename = '%s' where mac = '%s'", nickname, mac) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function get_dev_nick_name(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select devicename, orgname from maclist where mac like '%s'", mac) + db:busy_handler(database_busy) + local nickname = "" + for row in db:rows(sqlStr) do + if row[1] ~= "" then + nickname = row[1] + else + if row[2] ~= "" then + nickname = row[2] + end + end + end + db:close() + return nickname +end + +function initSmbBanTable() + local db = sqlite3.open(r10db) + local sqlStr = string.format("create table if not exists SmbBanTable(mac varchar(100), smb_ban varchar(100))") + db:exec(sqlStr) + return db:close() +end + +function addSmbBanList(mac, smb_ban) + local db = sqlite3.open(r10db) + local sqlStr = string.format("insert into SmbBanTable values('%s', '%s')", mac, smb_ban) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function fetchSmbBanList() + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from SmbBanTable where smb_ban = 'true'") + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["mac"] = row[1] + }) + end + end + db:close() + return result +end + +function deleteSmbBanList(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from SmbBanTable where mac = '%s' and smb_ban = 'true'", mac) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function fetchDenyDeviceInfo(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from maclist where mac = '%s'", mac) + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["mac"] = row[1], + ["orgname"] = row[2], + ["devicename"] = row[3], + ["ip"] = row[4] + }) + end + end + db:close() + return result +end + +function change_maclist_table() + local db = sqlite3.open(r10db) + local sqlStr = string.format("ALTER TABLE maclist ADD COLUMN ip varchar(100)") + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function fetchAllDeviceInfo() + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from maclist") + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["mac"] = row[1], + ["orgname"] = row[2], + ["devicename"] = row[3] + }) + end + end + db:close() + return result +end + +function updateDeviceOrgname(mac, orgname) + local db = sqlite3.open(r10db) + local sqlStr = string.format("update maclist set orgname = '%s' where mac = '%s'", orgname, mac) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function saveDeviceInfo(mac, orgname, devicename, deviceip) + local db = sqlite3.open(r10db) + local fetch = string.format("select * from maclist where mac = '%s'", mac) + db:busy_handler(database_busy) + local exist = false + for row in db:rows(fetch) do + if row then + exist = true + end + end + local sqlStr + if not exist then + sqlStr = string.format("insert into maclist values('%s','%s','%s', '%s')", mac, orgname, devicename, deviceip) + else + sqlStr = string.format("update maclist set mac = '%s', orgname = '%s', devicemame = '%s', ip = '%s' where mac = '%s'", mac, orgname, devicename, deviceip, mac) + end + db:exec(sqlStr) + return db:close() +end + +function initBatchFileTable() + local db = sqlite3.open(r10db) + local sqlStr = string.format("create table if not exists batchFilesTables(hashCode varchar(100), IMEI varchar(100))") + db:exec(sqlStr) + return db:close() +end + +function fetchAllFilesIndex(ID, path) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from FilesListTable where ID = '%s' and path = '%s'", ID, path) + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["name"] = row[3] + }) + end + end + db:close() + return result +end + +function fetchAllFilesList(ID, start, fetchEnd, path) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from FilesListTable where ID = '%s' and path = '%s' ORDER BY isfile, name limit '%s' offset '%s' ", ID, path, fetchEnd, start) + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["name"] = row[3], + ["isfile"] = row[4], + ["size"] = row[5], + ["time"] = row[6] + }) + end + end + db:close() + return result +end + + + +function addBatchFile(hashCode, IMEI) + local db = sqlite3.open(r10db) + local sqlStr = string.format("insert into batchFilesTables values('%s', '%s')", hashCode, IMEI) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function fetchAllBatchFile(IMEI) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from batchFilesTables where IMEI = '%s'",IMEI ) + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["hashCode"] = row[1] + }) + end + end + db:close() + return result +end + +function fetchBatchFileEndFlag(flag, IMEI) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from batchFilesTables where hashCode = '%s' and IMEI = '%s'", flag, IMEI) + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + result = { + ["hashCode"] = row[1] + } + end + end + db:close() + return result +end + +function deleteBatchFileEndFlag(flag, IMEI) + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from batchFilesTables where hashCode = '%s' and IMEI = '%s'", flag, IMEI) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function deleteBatchFile(IMEI) + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from batchFilesTables where IMEI = '%s'", IMEI) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function init_arp_table() + local db = sqlite3.open(r10db) + local sqlStr = string.format("create table if not exists arp(mac varchar(18), ip varchar(16))") + db:exec(sqlStr) + return db:close() +end + +function fetch_arp_mac(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from arp where mac like '%s'", mac) + db:busy_handler(database_busy) + local result = "" + for row in db:rows(sqlStr) do + if row then + result = row[1] + end + end + db:close() + return result +end + +function insert_arp_macip(mac, ip) + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from ") + sqlStr = string.format("insert into arp values('%s', '%s')", mac, ip) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function delete_arp_all_mac() + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from arp") + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function init_wireless_device_table() + local db = sqlite3.open(r10db) + local sqlStr = string.format("create table if not exists wireless_table(mac varchar(100))") + db:exec(sqlStr) + return db:close() +end + +function fetch_wireless_device_mac(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from wireless_table where mac = '%s'", mac) + db:busy_handler(database_busy) + local result = "" + for row in db:rows(sqlStr) do + if row then + result = row[1] + end + end + db:close() + return result +end + +function fetch_all_wireless_device() + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from wireless_table") + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["mac"] = row[1] + }) + end + end + db:close() + return result +end + +function insert_wireless_device_mac(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("insert into wireless_table values('%s')", mac) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function init_wire_device_table() + local db = sqlite3.open(r10db) + local sqlStr = string.format("create table if not exists wire_table(mac varchar(100), ip varchar(100))") + db:exec(sqlStr) + return db:close() +end + +function fetch_wire_device_mac(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from wire_table where mac = '%s'", mac) + db:busy_handler(database_busy) + local result = "" + for row in db:rows(sqlStr) do + if row then + result = row[1] + end + end + db:close() + return result +end + +function fetch_all_wire_device() + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from wire_table") + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["mac"] = row[1], + ["ip"] = row[2] + }) + end + end + db:close() + return result +end + +function insert_wire_device_mac(mac, ip) + local db = sqlite3.open(r10db) + local sqlStr = string.format("insert into wire_table values('%s','%s')", mac, ip) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function update_wire_device_ip(mac, ip) + local db = sqlite3.open(r10db) + local sqlStr = string.format("update wire_table set ip = '%s' where mac = '%s'", ip, mac) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function delete_wire__device(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from wire_table where mac = '%s'", mac) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function init_access_token_table() + local db = sqlite3.open(r10db) + local sqlStr = string.format("create table if not exists accessTokenTable(token varchar(100), expireTime bigint)") + db:exec(sqlStr) + return db:close() +end + +function add_access_token(token, expireTime) + local db = sqlite3.open(r10db) + local sqlStr = string.format("insert into accessTokenTable values('%s', %d)", token, expireTime) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function fetch_access_token() + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from accessTokenTable") + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["token"] = row[1], + ["expireTime"] = row[2] + }) + end + end + db:close() + return result +end + +function update_access_token(oldToken, newToken, expireTime) + local db = sqlite3.open(r10db) + local sqlStr = string.format("update accessTokenTable set token = '%s', expireTime = %d where token = '%s'", newToken, expireTime, oldToken) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function delete_access_token() + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from accessTokenTable") + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function initBluetoothTable() + local db = sqlite3.open(r10db) + local sqlStr = string.format("create table if not exists blemeshtable(id varchar(100), mac varchar(100), key varchar(100), name varchar(100), deviceType varchar(100), len varchar(100))") + db:exec(sqlStr) + return db:close() +end + +function addBluetoothDevice(id, mac, key, name, deviceType, len) + local db = sqlite3.open(r10db) + local sqlStr = string.format("insert into blemeshtable values('%s', '%s', '%s', '%s', '%s', '%s')", id, mac, key, name, deviceType, len) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function fetchAllBluetoothDevice() + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from blemeshtable") + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["mac"] = row[2], + ["deviceType"] = row[5] + }) + end + end + db:close() + return result +end + +function deleteBluetoothDevice(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from blemeshtable where mac = '%s'", mac) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function updateBluetoothDevice(id, key, name, len, mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("update blemeshtable set id = '%s', key = '%s', name = '%s', len = '%s' where mac = '%s'", id, key, name, len, mac) + db:busy_handler(database_busy) + db:exec(sqlStr) + return db:close() +end + +function fetchBluetoothDevice(mac) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from blemeshtable where mac = '%s'", mac) + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["id"] = row[1], + ["mac"] = row[2], + ["deviceType"] = row[5], + ["name"] = row[4] + }) + end + end + db:close() + return result +end + +function fetchBluetoothDeviceKey() + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from blemeshtable where key != ''") + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["mac"] = row[2], + ["key"] = row[3] + }) + end + end + db:close() + return result +end + +function getBluetoothDevice(id) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from blemeshtable where id = '%s'", id) + db:busy_handler(database_busy) + local result = "" + for row in db:rows(sqlStr) do + if row then + result = row[2] + end + end + db:close() + return result +end + +function fetchAllBleMeshDevice() + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from blemeshtable where id !=''") + db:busy_handler(database_busy) + local result = {} + for row in db:rows(sqlStr) do + if row then + table.insert(result,{ + ["mac"] = row[2], + ["deviceType"] = row[5], + ["name"] = row[4] + }) + end + end + db:close() + return result +end + +function getBleDeviceNameLength(id) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from blemeshtable where id = '%s'", id) + db:busy_handler(database_busy) + local result = "" + for row in db:rows(sqlStr) do + if row then + result = row[6] + end + end + db:close() + return result +end +--[[ +function initBleTimerTable() + local db = sqlite3.open(r10db) + local sqlStr = string.format("create table if not exists bletimertable(id varchar(100), timer_id varchar(100), flag varchar(100), start_time varchar(100), end_time varchar(100))") + db:exec(sqlStr) + return db:close() +end + +function addBleTimer(id, timer_id, flag, start_time, end_time) + local db = sqlite3.open(r10db) + local sqlStr = string.format("insert into bletimertable values('%s', '%s', '%s', '%s', '%s')", id, timer_id, flag, start_time, end_time) + db:exec(sqlStr) + return db:close() +end + +function deleteBleTimer(id, timer_id) + local db = sqlite3.open(r10db) + local sqlStr = string.format("delete from bletimertable where id = '%s' and timer_id = '%s'", id, timer_id) + db:exec(sqlStr) + return db:close() +end + +function getBleTimerId(id, timer_id) + local db = sqlite3.open(r10db) + local sqlStr = string.format("select * from bletimertable where id = '%s' and timer = '%s'", id, timer_id) + local result = "" + for row in db:rows(sqlStr) do + if row then + result = row[2] + end + end + db:close() + return result +end +]] \ No newline at end of file diff --git a/Me_Lua/h10/meizu/disk.lua b/Me_Lua/h10/meizu/disk.lua new file mode 100644 index 0000000..1b1cfc8 --- /dev/null +++ b/Me_Lua/h10/meizu/disk.lua @@ -0,0 +1,63 @@ +module("meizu.disk", package.seeall) + +local bfs = require "meizu.bfs" +local exec_cmd_in_sh = bfs.exec_cmd_in_sh +local lue = require("luci.util").exec + +function get_disk_space() + local lu = require("luci.util") + local cmd = "df -k | grep ' /mnt' | awk '{printf $2}'" + local disk = lue(cmd) + if disk ~= "" then + return disk + else + return "0" + end +end + +function get_available_disk() + local lu = require("luci.util") + local cmd = "df -k | grep ' /mnt' | awk '{printf $4}'" + local disk = lue(cmd) + if disk ~= "" then + return disk + else + return "0" + end +end + +function get_info_imp() + local ret = {} + ret["total"] = get_disk_space() + ret["free"] = get_available_disk() + return ret; +end + +function nw_get_disk_info() + luci.http.prepare_content("application/json") + local ret = get_info_imp() + luci.http.write_json(ret) +end + +function ww_get_disk_info() + local res = {} + res = get_info_imp() + return res +end + +function disk_formatting() + local result = {} + result["result"] = false + local cmd = [[ls /dev/sda |grep -E "/dev/sd.$" |wc -l|awk '{printf $1}']] + local res = lue(cmd) + + if res == "1" then + result["result"] = true + luci.http.write_json(result) + local cmd = "hd_part.sh /dev/sda;echo $?" + exec_cmd_in_sh(cmd) + else + result["code"] = res + luci.http.write_json(result) + end +end diff --git a/Me_Lua/h10/meizu/dlfs.lua b/Me_Lua/h10/meizu/dlfs.lua new file mode 100644 index 0000000..ef2b32f --- /dev/null +++ b/Me_Lua/h10/meizu/dlfs.lua @@ -0,0 +1,670 @@ +module("meizu.dlfs", package.seeall) +-- download functions + +local cjson = require "cjson" +local lfs = require "lfs" +local bfs = require "meizu.bfs" +local RC = require "meizu.r10config" +local nixio = require "nixio" + +local b64dec = bfs.b64dec +local bind_router = bfs.bind_router +local cal_str_md5 = bfs.cal_str_md5 +local data_to_json = bfs.data_to_json +local exec_cmd_in_sh = bfs.exec_cmd_in_sh +local exec_reboot = bfs.exec_reboot +local get_device_SN = bfs.get_device_SN +local get_device_version = bfs.get_device_version +local get_https_data = bfs.get_https_data +local rts_get_access_token = bfs.rts_get_access_token +local set_passwd = bfs.set_passwd +local silent_upgrade = bfs.silent_upgrade +local table_merge = bfs.table_merge + +local aria2rpc = "http://127.0.0.1:6800/jsonrpc" +local httpreq = require("socket.http").request +local lue = require("luci.util").exec + +function aria2_make_req_param(method, gid) + local p = [[{"jsonrpc":"2.0", "method":"]] + p = p..method..[[", ]] + p = p..[["id":1, "params":["]] + p = p..gid..'"]}' + p = p..'{"Accept=application/json, text/javascript, */*; q=0.01"}' + p = p..'{"Accept-Encoding=gzip, deflate"}' + p = p..'{"Content-Type=application/x-www-form-urlencoded; charset=UTF-8"}' + p = p..'{"Pragma=no-cache"}' + p = p..'{"Cache-Control=no-cache"}' + + return p +end + +function aria2_make_status_param(method, params) + local p = [[{"jsonrpc":"2.0", "method":"]] + p = p..method..[[", ]] + p = p..[["id":1]] + if params == "" then + p = p..'}' + else + p = p..[[, "params":[]] + p = p..params..']}' + end + p = p..'{"Accept=application/json, text/javascript, */*; q=0.01"}' + p = p..'{"Accept-Encoding=gzip, deflate"}' + p = p..'{"Content-Type=application/x-www-form-urlencoded; charset=UTF-8"}' + p = p..'{"Pragma=no-cache"}' + p = p..'{"Cache-Control=no-cache"}' + + return p +end + +function aria2_success_res(command, gid, status) + local res = [[{"result":true, "command":"]]..command..[[", "gid":"]]..gid..[[", "message":"]]..status..[["}]] + + return res +end + +function aria2_failed_res(command, gid, status) + local res = [[{"result":flase, "command":"]]..command..[[", "gid":"]]..gid..[[", "message":"]]..status..[["}]] + + return res +end + +function aria2_download_task_pause(gid, command) + local param = aria2_make_req_param("aria2.pause", gid) + local res, code, headers, status = httpreq(aria2rpc, param) + local success_res = aria2_success_res(command, gid, status) + local failed_res = aria2_failed_res(command, gid, status) + + if code == 200 then + return success_res + else + return failed_res + end +end + +function aria2_download_task_unpause(gid, command) + local param = aria2_make_req_param("aria2.unpause", gid) + local res, code, headers, status = httpreq(aria2rpc,param) + local success_res = aria2_success_res(command, gid, status) + local failed_res = aria2_failed_res(command, gid, status) + + if code == 200 then + return success_res + else + return failed_res + end +end + +function aria2_download_task_remove(gid, command) + local param = aria2_make_req_param("aria2.removeDownloadResult", gid) + local res, code, headers, status = httpreq(aria2rpc,param) + local success_res = aria2_success_res(command, gid, status) + local failed_res = aria2_failed_res(command, gid, status) + + if code == 200 then + return success_res + else + return failed_res + end +end + +function aria2_get_active_list() + local result = {} + local param = aria2_make_status_param("aria2.tellActive", "") + local res, code, headers, status = httpreq(aria2rpc, param) + + if code == 200 then + local jsd = cjson.decode(res) + for key, value in pairs(jsd.result) do + local data = {status = "", speed = nil, total = nil, + completed = nil, gid = "", file = ""} + + data.status = value.status + data.speed = tonumber(value.downloadSpeed) + data.total = tonumber(value.totalLength) + data.completed = tonumber(value.completedLength) + data.gid = value.gid + local jsd = cjson.encode(value.files) + jsd = string.sub(jsd, 2, -2) + local fn = cjson.decode(jsd) + data.file = "" + if string.match(fn.path, ".+/([^/]*%.%w+)$") then + data.file = string.match(fn.path, ".+/([^/]*%.%w+)$") + end + table.insert(result, data) + end + end + + return result +end + +function aria2_get_pause_list() + local param = aria2_make_status_param("aria2.tellWaiting", "0, 1000") + local res, code, headers, status = httpreq(aria2rpc,param) + local result = {} + if code == 200 then + local jsd = cjson.decode(res) + + for key, value in pairs(jsd.result) do + local data = {status = "", speed = nil, total = nil, + completed = nil, gid = "", file = ""} + data.status = value.status + data.speed = tonumber(value.downloadSpeed) + data.total = tonumber(value.totalLength) + data.completed = tonumber(value.completedLength) + data.gid = value.gid + local jsd = cjson.encode(value.files) + jsd = string.sub(jsd, 2, -2) + local fn = cjson.decode(jsd) + data.file = "" + if string.match(fn.path, ".+/([^/]*%.%w+)$") then + data.file = string.match(fn.path, ".+/([^/]*%.%w+)$") + end + table.insert(result, data) + end + end + + return result; +end + +function aria2_get_history_list() + local param = aria2_make_status_param("aria2.tellStopped", "0, 1000") + local result = {} + local res, code, headers, status = httpreq(aria2rpc, param) + if code == 200 then + local jsd = cjson.decode(res) + for key, value in pairs(jsd.result) do + local data = {status = "", speed = nil, total = nil, + completed = nil, gid = "", file = ""} + data.speed = tonumber(value.downloadSpeed) + data.total = tonumber(value.totalLength) + data.completed = tonumber(value.completedLength) + local jsd = cjson.encode(value.files) + jsd = string.sub(jsd, 2, -2) + local fn = cjson.decode(jsd) + data.status = value.status + data.gid = value.gid + data.file = "" + if string.match(fn.path, ".+/([^/]*%.%w+)$") then + data.file = string.match(fn.path, ".+/([^/]*%.%w+)$") + end + table.insert(result, data) + end + end + + return result +end + +function aria2_download_task_start(url) + local param = '[{"jsonrpc":"2.0", "method":"aria2.addUri", "id":"1",'.. + '"params":[['..'"'..url..'"'.."]]}]" + local res, code, headers, status = httpreq(aria2rpc, param) + local jsd = nil + if code == 200 then + res = string.sub(res, 2, -2) + jsd = cjson.decode(res) + end + local success_res = '{"result":true, "gid":'..'"'..jsd.result..'"'.. + ', "message":'..'"'..status..'"'.."}" + local failed_res = '{"result":false, "message":'..'"'..status..'"'.."}" + + if code == 200 then + return success_res + else + return failed_res + end +end + +function thunder_clean_list_log() + if nixio.fs.access("/tmp/tdal.log") then + nixio.fs.unlink("/tmp/tdal.log") + end + if nixio.fs.access("/tmp/tdhl.log") then + nixio.fs.unlink("/tmp/tdhl.log") + end +end + +function thunder_download_task_pause(gid, command) + thunder_clean_list_log() + local success_res = '{"result":true, "command":'..'"'..command..'"'.. + ', "gid":'..'"'..gid..'"'.. + ', "message":'..'"success"'.."}" + local cmd = "/usr/bin/xunleiR.py pause "..gid + local ret = lue(cmd) + + return success_res +end + +function download_task_pause(gid, command) + if string.match(gid, "^tdid_") then + local tdid = string.sub(gid, 6) + return thunder_download_task_pause(tdid, command) + else + return aria2_download_task_pause(gid, command) + end +end + +function thunder_download_task_unpause(gid, command) + thunder_clean_list_log() + local success_res = '{"result":true, "command":'.. + '"'..command..'"'..', "gid":'.. + '"'..gid..'"'..', "message":'..'"success"'.."}" + local cmd = "/usr/bin/xunleiR.py start "..gid + local ret = lue(cmd) + + return success_res +end + +function download_task_unpause(gid, command) + if string.match(gid, "^tdid_") then + local tdid = string.sub(gid, 6) + return thunder_download_task_unpause(tdid, command) + else + return aria2_download_task_unpause(gid, command) + end +end + +function thunder_download_task_remove(gid, command) + thunder_clean_list_log() + local success_res = '{"result":true, "command":'.. + '"'..command..'"'..', "gid":'.. + '"'..gid..'"'..', "message":'..'"success"'.."}" + --local cmd = "/usr/bin/xunleiR.py remove "..gid + local cmd = "/usr/bin/xunleiR.py delete "..gid + local ret = lue(cmd) + require "MZLog".log(3, ret) + + return success_res +end + +function download_task_remove(gid, command) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, gid) + require "MZLog".log(3, debug.getinfo(1).currentline) + if string.match(gid, "^tdid_") then + local tdid = string.sub(gid, 6) + return thunder_download_task_remove(tdid, command) + else + return aria2_download_task_remove(gid, command) + end +end + +function get_pause_list() + local result = aria2_get_pause_list() + local ret_msg = "" + if nil ~= next(result) then + --result = cjson.encode(result) + local jsr = data_to_json(result) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, jsr) + require "MZLog".log(3, debug.getinfo(1).currentline) + ret_msg = '{"result":true, "message":'..jsr.."}" + else + ret_msg = '{"result":false, "message":[]}' + end + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, ret_msg) + require "MZLog".log(3, debug.getinfo(1).currentline) + + return ret_msg +end + +function nw_get_pause_list() + local data = get_pause_list() + luci.http.write(data) +end + +function thunder_get_bind_code() + local ret = {} + local lue = require"luci.util".exec + local cmd = [[/usr/bin/xunleiR.py sysinfo|awk -F',' '{print $5}']] + local code = lue(cmd) + ret = '{"code":'..code..'}' + + return ret +end + +function nw_thunder_get_bind_code() + local data = thunder_get_bind_code() + luci.http.write(data) +end + +function ww_thunder_get_bind_code() + return thunder_get_bind_code() +end + +function thunder_state_code(code) + local ret = "active" + if code == 0 or code == 8 or code == 13 or code == 14 or code == 37 then + ret = "active" + end + if code == 9 or code == 10 then + ret = "paused" + end + if code == 11 or code == 15 then + ret = "complete" + end + + return ret +end + +function thunder_localpath_translate(path) + if type(path) == "string" then + path = string.gsub(path, "/opt/xware/mnt/", "/router/Thunder/") + end + return path +end + +function thunder_get_active_list() + local cmd = "/usr/bin/xunleiR.py list" + local ret + require "MZLog".log(3, debug.getinfo(1).currentline) + if nixio.fs.access("/tmp/tdal.log") then + local fp = io.open("/tmp/tdal.log", "r") + local data = fp:read("*a") + ret = data + fp:close() + else + ret = lue(cmd) + local fp = io.open("/tmp/tdal.log", "wb") + fp:write(ret) + fp:close() + end + local result = {} + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + if ret then + require "MZLog".log(3, debug.getinfo(1).currentline) + local jsd = cjson.decode(ret) + local tasks = jsd.tasks + for k, v in pairs(tasks) do + local data = {} + if (_G.next(v) ~= nil) then + data.speed = v.speed + data.status = thunder_state_code(v.state) + data.total = tonumber(v.size) + data.completed = tonumber(data.total * tonumber(v.progress)/10000) + data.file = v.name + data.path = thunder_localpath_translate(v.path) + data.gid = 'tdid_'..v.id + end + table.insert(result, data) + end + end + + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, data_to_json(result)) + require "MZLog".log(3, debug.getinfo(1).currentline) + return result +end + +function thunder_get_rlist() + thunder_clean_list_log() + local cmd = "/usr/bin/xunleiR.py rlist" + local ret = lue(cmd) + local jsd = cjson.decode(ret) + local tasks = jsd.tasks + local result = {} + for k, v in pairs(tasks) do + local data = {} + if (_G.next(v) ~= nil) then + data.speed = v.speed + data.status = thunder_state_code(v.state) + data.total = tonumber(v.size) + data.completed = tonumber(data.total * tonumber(v.progress)/10000) + data.file = v.name + data.gid = 'tdid_'..v.id + end + table.insert(result, data) + end + + return result +end + +function get_active_list(start, refine_cnt) + local s = 0 + local cnt + if start then + s = start + end + local result = {} + local aria2_alist = aria2_get_active_list() + local thunder_alist = thunder_get_active_list() + local aria2_plist = aria2_get_pause_list() + --local thunder_rlist = thunder_get_rlist() + if _G.next(aria2_alist) then + result = table_merge(result, aria2_alist) + end + if _G.next(thunder_alist) then + result = table_merge(result, thunder_alist) + end + if _G.next(aria2_plist) then + result = table_merge(result, aria2_plist) + end + + local ret_msg = {} + local total = require("table").getn(result) + ret_msg["total"] = total + ret_msg["result"] = false + local ret = {} + if _G.next(result) then + if refine_cnt then + cnt = refine_cnt + else + cnt = total + end + local pos = 0 + for k, v in pairs(result) do + if pos >= s and (pos - s + 1 <= cnt) then + table.insert(ret, v) + pos = pos + 1 + end + end + ret_msg["result"] = true + ret_msg["message"] = ret + else + ret_msg["message"] = "[]" + end + ret_msg["start"] = s + if ret and type(ret) == "table" and _G.next(ret) then + ret_msg["count"] = require("table").getn(ret) + else + ret_msg["count"] = 0 + end + ret_msg = data_to_json(ret_msg) + require "MZLog".log(3, ret_msg) + + return ret_msg +end + +function nw_get_active_list() + local data = get_active_list() + luci.http.write(data) +end + +function thunder_get_history_list() + local cmd = "/usr/bin/xunleiR.py clist" + local ret + if nixio.fs.access("/tmp/tdhl.log") then + local fp = io.open("/tmp/tdhl.log", "r") + local data = nixio.fs.readfile("/tmp/tdhl.log") + ret = data + else + ret = lue(cmd) + local fp = io.open("/tmp/tdhl.log", "wb") + fp:write(ret) + fp:close() + end + + local jsd = cjson.decode(ret) + local tasks = jsd.tasks + local result = {} + for k, v in pairs(tasks) do + local data = {} + if (_G.next(v) ~= nil) then + data.speed = v.speed + data.total = tonumber(v.size) + data.completed = v.size + data.status = thunder_state_code(v.state) + data.file = v.name + data.path = thunder_localpath_translate(v.path) + data.gid = 'tdid_'..v.id + end + table.insert(result, data) + end + return result +end + +function get_history_list(start, refine_cnt) + local s = 0 + local cnt + require "MZLog".log(3, debug.getinfo(1).currentline) + if start then + s = start + require "MZLog".log(3, start) + end + if refine_cnt then + require "MZLog".log(3, refine_cnt) + end + require "MZLog".log(3, debug.getinfo(1).currentline) + local result = {} + local aria2_ret = aria2_get_history_list() + local thunder_ret = thunder_get_history_list() + + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, data_to_json(aria2_ret)) + require "MZLog".log(3, debug.getinfo(1).currentline) + + if nil ~= _G.next(aria2_ret) then + table_merge(result, aria2_ret) + end + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, data_to_json(thunder_ret)) + require "MZLog".log(3, debug.getinfo(1).currentline) + if _G.next(thunder_ret) then + table_merge(result, thunder_ret) + end + + require "MZLog".log(3, debug.getinfo(1).currentline) + local total = require("table").getn(result) + local ret_msg = {} + require "MZLog".log(3, debug.getinfo(1).currentline) + ret_msg["total"] = total + ret_msg["result"] = false + if _G.next(result) then + require "MZLog".log(3, debug.getinfo(1).currentline) + local cnt + if refine_cnt then + cnt = refine_cnt + else + cnt = total + end + local ret = {} + local pos = 0 + for k, v in pairs(result) do + if pos >= s and (pos - s + 1 <= cnt) then + table.insert(ret, v) + pos = pos + 1 + end + end + ret_msg["count"] = require("table").getn(ret) + local jsd = data_to_json(ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, jsd) + require "MZLog".log(3, debug.getinfo(1).currentline) + ret_msg["result"] = true + --ret_msg["message"] = jsd + ret_msg["message"] = ret + else + ret_msg["message"] = "[]" + end + ret_msg["start"] = s + if ret and type(ret) == "table" and _G.next(ret) then + ret_msg["count"] = require("table").getn(ret) + else + ret_msg["count"] = 0 + end + require "MZLog".log(3, debug.getinfo(1).currentline) + ret_msg = data_to_json(ret_msg) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, ret_msg) + require "MZLog".log(3, debug.getinfo(1).currentline) + + return ret_msg +end + +function nw_get_history_list() + local data = get_history_list() + luci.http.write(data) +end + +function thunder_download_task_start(url) + thunder_clean_list_log() + local ret = "" + local cmd = [[/usr/bin/xunleiR.py download ']]..url..[[']] + require "MZLog".log(3, cmd) + ret = lue(cmd) + require "MZLog".log(3, ret) + local jsr = cjson.decode(ret) + ret = {} + ret["message"] = "" + ret["result"] = false + if jsr and jsr.rtn then + require "MZLog".log(3, jsr.rtn) + ret["rtn"] = jsr.rtn + if jsr.rtn == 0 or jsr.rtn == 202 then + ret["result"] = true + end + end + + if jsr and jsr.id then + ret["gid"] = "tdid_"..jsr.id + else + ret["gid"] = "tdid_0" + end + + return data_to_json(ret) +end + +function download_task_start(url, dltype) + require "MZLog".log(3, url) + require "MZLog".log(3, dltype) + local res = "" + if dltype == "thunder" then + res = thunder_download_task_start(url) + else + res = aria2_download_task_start(url) + end + require "MZLog".log(3, res) + + return res +end + +function nw_download_task_start() + local url = luci.http.formvalue("url") + local dltype = luci.http.formvalue("type") + local res = download_task_start(url, dltype) + luci.http.write(res) + + return res +end + +function download_task_operate(gid, command) + if command == "downloadpause" then + return download_task_pause(gid, command) + elseif command == "downloadunpause" then + return download_task_unpause(gid, command) + elseif command == "downloadremove" then + return download_task_remove(gid, command) + end +end + +function nw_download_task_operate() + local command = luci.http.formvalue("command") + local gid = luci.http.formvalue("gid") + local ret = download_task_operate(gid, command) + + luci.http.write(ret) +end diff --git a/Me_Lua/h10/meizu/nwfs.lua b/Me_Lua/h10/meizu/nwfs.lua new file mode 100644 index 0000000..417c120 --- /dev/null +++ b/Me_Lua/h10/meizu/nwfs.lua @@ -0,0 +1,1747 @@ +module("meizu.nwfs", package.seeall) +--network functions + +local cjson = require "cjson" +local lfs = require "lfs" +local bfs = require "meizu.bfs" +local RC = require "meizu.r10config" + +local bind_router = bfs.bind_router +local data_to_json = bfs.data_to_json +local exec_cmd_in_sh = bfs.exec_cmd_in_sh +local exec_reboot = bfs.exec_reboot +local get_device_SN = bfs.get_device_SN +local get_device_version = bfs.get_device_version +local get_https_data = bfs.get_https_data +local rts_get_access_token = bfs.rts_get_access_token +local set_passwd = bfs.set_passwd +local silent_upgrade = bfs.silent_upgrade +local strsplit = bfs.strsplit +local b64dec = bfs.b64dec +local b64enc = bfs.b64enc + +local lue = require("luci.util").exec + +function get_connect_info() + --usr/lib/lua/luci/controller/admin/network.lua lease_status() + local rv = { } + local s = require "luci.tools.status" + + luci.http.prepare_content("application/json") + rv = s.dhcp_leases() + for k, v in pairs(rv) do + v.netswitch = "true" + v.diskswitch = "true" + v.netspeed = 0 + v.onnettime = 0 + v.netflow = 0 + end + luci.http.write_json(rv) +end + +function wifi_network(wifi_device_name) + local network = require "luci.model.network".init() + local wifi_net = network:get_wifinet(wifi_device_name) + if wifi_net then + local dev = wifi_net:get_device() + if dev then + return { + id = wifi_device_name, + name = wifi_net:shortname(), + up = wifi_net:is_up(), + mode = wifi_net:active_mode(), + ssid = wifi_net:active_ssid(), + bssid = wifi_net:active_bssid(), + encryption = wifi_net:active_encryption(), + encryption_src = wifi_net:get("encryption"), + frequency = wifi_net:frequency(), + bitrate = wifi_net:bitrate(), + ifname = wifi_net:ifname(), + assoclist = wifi_net:assoclist(), + country = wifi_net:country(), + key = wifi_net:get("key"), + key1 = wifi_net:get("key1"), + hidden = wifi_net:get("hidden"), + device = { + up = dev:is_up(), + device = dev:name(), + name = dev:get_i18n() + } + } + end + end + return {} +end + +function wifi_networks() + local result = {} + local network = require "luci.model.network".init() + local dev + for _, dev in ipairs(network:get_wifidevs()) do + local rd = { + up = dev:is_up(), + device = dev:name(), + name = dev:get_i18n(), + networks = {} + } + local wifi_net + for _, wifi_net in ipairs(dev:get_wifinets()) do + rd.networks[#rd.networks+1] = { + name = wifi_net:shortname(), + up = wifi_net:is_up(), + mode = wifi_net:active_mode(), + ssid = wifi_net:active_ssid(), + bssid = wifi_net:active_bssid(), + encryption = wifi_net:active_encryption(), + frequency = wifi_net:frequency(), + channel = wifi_net:channel(), + signal = wifi_net:signal(), + quality = wifi_net:signal_percent(), + noise = wifi_net:noise(), + bitrate = wifi_net:bitrate(), + ifname = wifi_net:ifname(), + assoclist = wifi_net:assoclist(), + country = wifi_net:country(), + key = wifi_net:get("key"), + key1 = wifi_net:get("key1"), + encryption_src = wifi_net:get("encryption"), + hidden = wifi_net:get("hidden"), + } + end + result[#result+1] = rd + end + return result +end + +function nw_get_wifi_settings() + luci.http.prepare_content("application/json") + local app_version = luci.http.formvalue("appVer") + if app_version == nil then + app_version = 0 + end + local list = get_wifi_settings(app_version) + luci.http.write(list) +end + +function ww_get_wifi_settings(app_version) + local list = get_wifi_settings(app_version) + --return data_to_json(list) + return list +end + +function get_wifi_settings(app_version) + local network = require "luci.model.network".init() + local info_list = {} + local wifis = wifi_networks() + for i,wifi_net in ipairs(wifis) do + local item = {} + local index = 1 + + if wifi_net.device == "wl0" then + local wifi_net_wl0 = network:get_wifinet('wl0.network1') + if wifi_net_wl0:get("disabled") == "1" then + item["status"] = "false" + else + item["status"] = "true" + end + end + + if wifi_net.device == "wl1" then + local wifi_net_wl1 = network:get_wifinet('wl1.network1') + if wifi_net_wl1:get("disabled") == "1" then + item["status"] = "false" + else + item["status"] = "true" + end + end + + local encryption = wifi_net.networks[index].encryption_src + local key = wifi_net.networks[index].key + if encryption == "wep-open" then + key = wifi_net.networks[index].key1 + if key:len()>4 and key:sub(0,2)=="s:" then + key = key:sub(3) + end + end + item["name"] = wifi_net.networks[index].ifname + item["ssid"] = wifi_net.networks[index].ssid + if key == nil then + key = "" + end + item["password"] = key + item["encryption"] = encryption + info_list[#wifis+1-i] = item + end + local guestwifi = get_guest_wifi(1) + if guestwifi then + table.insert(info_list, guestwifi) + end + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, info_list) + if tonumber(app_version) >= 5 then + return b64enc(cjson.encode(info_list)) + else + return cjson.encode(info_list) + end +end + +function get_wifi_ssids() + local wifis = wifi_networks() + local ssid1 = "" + local ssid2 = "" + for i, wifi_net in ipairs(wifis) do + if i == 1 then + ssid1 = wifi_net.networks[1].ssid + end + if i == 2 then + ssid2 = wifi_net.networks[1].ssid + end + end + + return ssid1, ssid2 +end + +function nw_wifi_settings() + + luci.http.prepare_content("application/json") + local data = luci.http.formvalue("data") + local app_version = luci.http.formvalue("appVer") + if app_version == nil then + app_version = 0 + end + local switch_2g = nil + local switch_5g = nil + local switch_guest = nil + local ssid_2g = nil + local ssid_5g = nil + local ssid_guest = nil + local pwd_2g = nil + local pwd_5g = nil + local pwd_guest = nil + local encry_2g = nil + local encry_5g = nil + local encry_guest = nil + + if tonumber(app_version) >= 5 then + local data = b64dec(data) + data = cjson.decode(data) + + for k, v in pairs(data) do + if v.name == "wl0" then + switch_2g = v.on + ssid_2g = v.ssid + pwd_2g = v.pwd + encry_2g = v.encryption + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + elseif v.name == "wl1" then + switch_5g = v.on + ssid_5g = v.ssid + pwd_5g = v.pwd + encry_5g = v.encryption + else + switch_guest = v.on + ssid_guest = v.ssid + pwd_guest = v.pwd + encry_guest = v.encryption + end + end + else + switch_2g = luci.http.formvalue("on1") + ssid_2g = luci.http.formvalue("ssid1") + pwd_2g = luci.http.formvalue("pwd1") + encry_2g = luci.http.formvalue("encryption1") + + switch_5g = luci.http.formvalue("on2") + ssid_5g = luci.http.formvalue("ssid2") + pwd_5g = luci.http.formvalue("pwd2") + encry_5g = luci.http.formvalue("encryption2") + + switch_guest = luci.http.formvalue("on3") + ssid_guest = luci.http.formvalue("ssid3") + pwd_guest = luci.http.formvalue("pwd3") + encry_guest = luci.http.formvalue("encryption3") + end + + local res = wifi_settings(switch_2g, ssid_2g, pwd_2g, encry_2g, switch_5g, ssid_5g, pwd_5g, encry_5g, switch_guest, ssid_guest, pwd_guest, encry_guest) + luci.http.write_json(res) +end + +function wifi_settings(switch_2g, ssid_2g, pwd_2g, encry_2g, switch_5g, ssid_5g, pwd_5g, encry_5g, switch_guest, ssid_guest, pwd_guest, encry_guest) + local result = {} + local res = {} + local details = {} + --local code = 0 + local code_2g = 0 + local code_5g = 0 + local code_guest = 0 + local code_2g = check_ssid(ssid_2g, 31) + local code_5g = check_ssid(ssid_5g, 31) + local code_guest = check_ssid(ssid_guest, 31) + local succeed_2g = false + local succeed_5g = false + local succeed_guest = false + + if switch_2g == "false" then + succeed_2g = set_wifi_basic_info(1, nil, nil, nil, switch_2g) + else + if code_2g == 1 then + succeed_2g = set_wifi_basic_info(1, ssid_2g, pwd_2g, encry_2g, switch_2g) + end + end + + if switch_5g == "false" then + succeed_5g = set_wifi_basic_info(2, nil, nil, nil, switch_5g) + else + if code_5g == 1 then + succeed_5g = set_wifi_basic_info(2, ssid_5g, pwd_5g, encry_5g, switch_5g) + end + end + + local wifirestart = true + if switch_guest == "true" then + switch_guest = 1 + if set_guest(1, ssid_guest, encry_guest, pwd_guest, 1, switch_guest) then + succeed_guest = true + --code = 0 + else + succeed_guest = false + wifirestart = false + end + elseif switch_guest == "false" then + switch_guest = 0 + if set_guest(1, nil, nil, nil, 0, switch_guest) then + succeed_guest = true + end + else + return nil + end + + if code_2g ~= 0 and code_5g ~= 0 and code_guest ~= 0 and succeed_2g ~= false + and succeed_5g ~= false and succeed_guest ~= false then + + res["result"] = true + if wifirestart then + fork_restart_wifi() + end + else + res["result"] = false + end + + return res +end + +function set_wifi_basic_info(wifi_index, ssid, password, encryption, on) + + local network = require "luci.model.network".init() + if wifi_index == 1 then + wifi_net = network:get_wifinet('wl0.network1') + wifi_dev = network:get_wifidev('wl0') + end + + if wifi_index == 2 then + wifi_net = network:get_wifinet('wl1.network1') + wifi_dev = network:get_wifidev('wl1') + end + + if wifi_net == nil then + return false + end + + if wifi_dev then + if on == "true" then + wifi_net:set("disabled", "0") + elseif on == "false" then + wifi_net:set("disabled", "1") + end + end + + if not is_str_nil(ssid) and check_ssid(ssid) then + wifi_net:set("ssid",ssid) + end + + local code = check_wifi_passwd(password,encryption) + if code == 0 then + wifi_net:set("encryption",encryption) + wifi_net:set("key",password) + if encryption == "none" then + wifi_net:set("key","") + elseif encryption == "wep-open" then + wifi_net:set("key1","s:"..password) + wifi_net:set("key",1) + end + elseif code > 1502 then + return false + end + + network:save("wireless") + network:commit("wireless") + return true +end + +function is_str_nil(str) + return (str == nil or str == "") +end + +function check_ssid(ssid) + if is_str_nil(ssid) then + return 0 + end + + return 1 + --[[ + if string.match(ssid,"^%w[%w_.-]*%w$") or string.match(ssid, "^%w$") or + string.match(ssid, "^%w[%w_.-]*$") or string.match(ssid,"^[%w_.-]*$") or + string.match(ssid, "^[%w_.-]*%w$") then + return 1 + else + return 0 + end + ]] +end + +function check_wifi_passwd(passwd,encryption) + if is_str_nil(encryption) or (encryption and encryption ~= "none" and is_str_nil(passwd)) then + return 1502 + end + if encryption == "psk" or encryption == "psk2" then + if passwd:len() < 8 then + return 1520 + end + elseif encryption == "mixed-psk" then + if passwd:len()<8 or passwd:len()>63 then + return 1521 + end + elseif encryption == "wep-open" then + if passwd:len()~=5 and passwd:len()~=13 then + return 1522 + end + end + --[[ + if passwd ~= "" then + local ret = string.match(passwd, "^%w[^&\\%%+]*%w$") or string.match(passwd, "^%w[^&\\%%+]*$") + if ret == nil or string.find(passwd,'"') then + return 1523 + end + end + ]] + return 0 +end + +function fork_restart_wifi() + local FORK_RESTART_WIFI = "sleep 1; /sbin/wifi >/dev/null 2>/dev/null; /etc/init.d/minidlna restart; /etc/init.d/samba restart; /usr/bin/gettraffic flush_wl_dev >/dev/null 2>/dev/null" + exec_cmd_in_sh(FORK_RESTART_WIFI) +end + +function fork_restart_network() + local FORK_RESTART_WORK= "/etc/init.d/network restart" + exec_cmd_in_sh(FORK_RESTART_WORK) +end + +function check_guest_wifi() + local uci = require("luci.model.uci").cursor() + local guest = uci:get_all("network", "eth0_3") + if guest then + return true + else + return false + end +end + +function set_guest(wifi_index, ssid, encryption, key, enabled, open) + local success = set_guest_wifi(wifi_index, ssid, encryption, key, enabled, open) + if not success then + return false + end + local networkrestart = true + if check_guest_wifi() then + networkrestart = false + end + if networkrestart then + local lanip = get_lan_ip() + local lan = lanip:gsub(".%d+.%d+$", "") + local cip = tonumber(lanip:match(".(%d+).%d+$")) + local nixio = require("nixio") + local bit = nixio.bit + cip = bit.bor(bit.band(1, cip + 1), bit.lshift(bit.rshift(cip, 1), 1)) + lanip = lan.."."..tostring(cip)..".1" + exec_cmd_in_sh("sleep 4; /usr/sbin/guest_ssid_network start "..lanip.." 255.255.255.0 >/dev/null 2>/dev/null") + else + fork_restart_wifi() + end + return true +end + +function set_guest_wifi(wifi_index, ssid, encryption, key, enabled, open) + local uci = require("luci.model.uci").cursor() + local wifinetid, ifname + local enabled = tonumber(enabled) == 1 and 1 or 0 + local open = tonumber(open) == 1 and 1 or 0 + if tonumber(wifi_index) == 1 then + wifinetid = "wl0iface1" + ifname = uci:get_all("wireless", "@wifi-iface[1]","ifname") + else + return false + end + guestwifi = uci:get_all("wireless", wifinetid) + if guestwifi then + guestwifi["ifname"] = ifname + if not is_str_nil(ssid) and check_ssid(ssid) then + guestwifi["ssid"] = ssid + end + if encryption and string.lower(tostring(encryption)) == "none" then + guestwifi["encryption"] = "none" + guestwifi["key"] = "" + end + if enabled == 1 then + guestwifi["disabled"] = 0 + elseif enabled == 0 then + guestwifi["disabled"] = 1 + else + end + + if open then + guestwifi["open"] = open + end + if encryption and string.lower(tostring(encryption)) ~= "none" and not is_str_nil(key) then + local check = check_wifi_passwd(key,encryption) + if check == 0 then + guestwifi["encryption"] = encryption + guestwifi["key"] = key + else + return false + end + end + else + if is_str_nil(ssid) or is_str_nil(encryption) then + return false + end + guestwifi = { + ["ifname"] = ifname, + ["network"] = "guest", + ["ssid"] = ssid, + ["mode"] = "ap", + ["encryption"] = encryption, + ["key"] = key, + ["open"] = open, + ["enabled"] = enabled + } + end + uci:section("wireless", "wifi-iface", wifinetid, guestwifi) + uci:commit("wireless") + return true +end + +function get_lan_ip() + local uci = require("luci.model.uci").cursor() + local lan = uci:get_all("network", "lan") + return lan.ipaddr +end + +function get_guest_wifi(wifiIndex) + local uci = require("luci.model.uci").cursor() + local index = tonumber(wifiIndex) + local status + local guestwifi + guestwifi = uci:get_all("wireless","wl0iface1") + if guestwifi then + if guestwifi.disabled == "1" then + status = "false" + else + status = "true" + end + + if guestwifi.key == nil then + guestwifi.key = "none" + end + + return { + ["name"] = "guest", + ["ssid"] = guestwifi.ssid, + ["encryption"] = guestwifi.encryption, + ["password"] = guestwifi.key, + ["status"] = status, + } + end + return guestwifi +end + +function macFormat(mac) + if mac then + return string.upper(string.gsub(mac, "-", ":")) + else + return "" + end +end + +function getAllWifiConnetDeviceDict() + local result = {} + for index = 1,3 do + local wifilist = getWifiConnectDeviceList(index) + for _, mac in pairs(wifilist) do + local item = {} + item['wifiIndex'] = index + result[macFormat(mac)] = item + end + end + return result +end + +function getWifiConnectDeviceList(wifiIndex) + local assoclist = {} + if tonumber(wifiIndex) == 1 then + assoclist = wifi_network('wl0.network1').assoclist or {} + elseif tonumber(wifiIndex) == 2 then + assoclist = wifi_network('wl1.network1').assoclist or {} + else + assoclist = wifi_network('wl0.network2').assoclist or {} + end + local dlist = {} + for mac, info in pairs(assoclist) do + table.insert(dlist, macFormat(mac)) + end + return dlist +end + +function getDHCPLists() + local NixioFs = require("nixio.fs") + local LuciUci = require("luci.model.uci") + local uci = LuciUci.cursor() + local result = {} + local leasefile = "/var/dhcp.leases" + uci:foreach("dhcp", "dnsmasq", + function(s) + if s.leasefile and NixioFs.access(s.leasefile) then + leasefile = s.leasefile + return false + end + end) + local dhcp = io.open(leasefile, "r") + if dhcp then + for line in dhcp:lines() do + if line then + local ts, mac, ip, name = line:match("^(%d+) (%S+) (%S+) (%S+)") + if name == "*" then + name = "" + end + if ts and mac and ip and name then + result[#result+1] = { + mac = macFormat(mac), + ip = ip, + name = name, + sp = 0 + } + end + end + end + dhcp:close() + return result + else + return false + end +end + +function getDHCPDict() + local dhcpDict = {} + local dhcpList = getDHCPLists() + for _,value in ipairs(dhcpList) do + dhcpDict[value.mac] = value + end + return dhcpDict +end + +function getDHCPIpDicts() + local dhcpDict = {} + local dhcpList = getDHCPLists() + for _,value in ipairs(dhcpList) do + dhcpDict[value.ip] = value + end + return dhcpDict +end + +function getDeviceInfoFromDB() + local dbfs = require("meizu.dbfs") + local result = {} + local deviceList = dbfs.fetchAllDeviceInfo() + if #deviceList > 0 then + for _, device in ipairs(deviceList) do + result[device.mac] = device + end + end + return result +end + +function is_device_online(ip) + local lu = require("luci.util") + --local cmd = "ping -W 2 -c 1 www.baidu.com > /dev/null ;echo -n $?" + local cmd = "ping -W 2 -c 1 " .. ip .. " > /dev/null ;echo -n $?" + local pingresult = lu.exec(cmd) + + local res = nil + if pingresult == "0" then + res = true + else + res = false + + end + + return res +end + +function get_connect_device_list() + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, require"socket".gettime()*1000) + local dbfs = require("meizu.dbfs") + dbfs.change_maclist_table() + local LuciUtil = require("luci.util") + local deviceList = {} + local dhcpDeviceDict = getDHCPDict() + local wifiDeviceDict = getAllWifiConnetDeviceDict() + -- local dhcpDevIpDict = getNetConnect() + + local blacklist0 = getMacfilterList(0) + if next(blacklist0) ~= nil then + for _, mac in pairs(blacklist0) do + local flag = 0 + for key, value in pairs(dhcpDeviceDict) do + if value.mac == mac then + flag = 1 + break + end + end + if flag == 0 then + local res = dbfs.fetchDenyDeviceInfo(mac) + if #res > 0 then + for _, device in ipairs(res) do + dhcpDeviceDict[device.mac] = device + end + end + end + end + end + + local cmd = [[cat /proc/net/arp |grep br-lan|awk '{print $1","$4}']] + local ipmacs = {} + local devs = lue(cmd) + if devs ~= "" then + ipmacs = strsplit(devs, '\n') + end + ipmacs[#ipmacs] = nil + local wire_table = {} + for k, v in pairs(ipmacs) do + local ipmac = strsplit(v, ',') + local ip = ipmac[1] + local mac = string.upper(ipmac[2]) + local flag = false + local res = dbfs.fetch_all_wireless_device() + + if #res > 0 then + for key, value in pairs(res) do + if mac == value.mac then + flag = true + break + end + end + end + if flag == false then + local res = {} + res.mac = mac + res.ip = ip + res.name = "" + table.insert(wire_table, res) + end + end + + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, wire_table) + for k, v in pairs(wire_table) do + local flag = false + for key, value in pairs(dhcpDeviceDict) do + local mac = macFormat(key) + + if v.mac == mac then + local dhcpinfo = dhcpDeviceDict[mac] + v["name"] = dhcpinfo.name + dbfs.updateDeviceOrgname(mac, dhcpinfo.name) + flag = true + break + end + end + if flag == false then + dhcpDeviceDict[v.mac] = v + end + end + + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + + local deviceDBDict = getDeviceInfoFromDB() + for key, item in pairs(dhcpDeviceDict) do + local item = {} + local mac = macFormat(key) + local deviceDB = deviceDBDict[mac] + local dhcpinfo = dhcpDeviceDict[mac] + if deviceDB ~= nil then + item["devicename"] = deviceDB.orgname + if deviceDB.devicename ~= '' then + item["devicename"] = deviceDB.devicename + end + else + item["devicename"] = dhcpinfo.name + dbfs.saveDeviceInfo(mac, dhcpinfo.name, "", dhcpinfo.ip) + end + + local black0 = blacklist0[mac] + if black0 ~= nil then + item["enable"] = false + else + item["enable"] = true + end + + local wifiType = wifiDeviceDict[mac] + local online = dhcpDeviceDict[mac] + if wifiType ~= nil then + if wifiType.wifiIndex == 1 or wifiType.wifiIndex == 3 then + item["type"] = "2.4G" + elseif wifiType.wifiIndex == 2 then + item["type"] = "5G" + end + elseif wifiType == nil and online ~= nil and black0 == nil then + local wireless_res = dbfs.fetch_wireless_device_mac(mac) + if wireless_res == "" and mac ~= "00:00:00:00:00:00" then + item["type"] = "wire" + else + item["type"] = "unknown" + end + else + item["type"] = "unknown" + end + + if online ~= nil and black0 == nil and item["type"] ~= "unknown" then + item["online"] = true + else + item["online"] = false + end + + item["ip"] = dhcpinfo.ip + item["mac"] = mac + -- item["netSpeed"] = tostring(dhcpinfo.ip.rx_bytes or 0) + deviceList[#deviceList+1] = item + end + --[[ + if blacklist0 ~= nil then + for _, mac in pairs(blacklist0) do + local item = {} + local mac = macFormat(mac) + local deviceDB = deviceDBDict[mac] + local dhcpdevice = dhcpDeviceDict[mac] + if dhcpdevice == nil then + if deviceDB ~= nil then + item["devicename"] = deviceDB.orgname + if deviceDB.devicename ~= '' then + item["devicename"] = deviceDB.devicename + end + end + local wifiType = wifiDeviceDict[mac] + if wifiType ~= nil then + if wifiType.wifiIndex == 1 then + item["type"] = "2.4G" + elseif wifiType.wifiIndex == 2 then + item["type"] = "5G" + end + else + item["type"] = "lan" + end + item["enable"] = false + item["online"] = false + item["ip"] = "null" + item["mac"] = mac + --item["diskaccess"] = false + -- item["netSpeed"] = tostring(dhcpinfo.ip.rx_bytes or 0) + deviceList[#deviceList+1] = item + end + end + end + if blacklist1 ~= nil then + for _,mac in pairs(blacklist1) do + local item = {} + local mac = macFormat(mac) + local deviceDB = deviceDBDict[mac] + local dhcpdevice = dhcpDeviceDict[mac] + if dhcpdevice == nil then + if deviceDB ~= nil then + item["devicename"] = deviceDB.orgname + if deviceDB.devicename ~= '' then + item["devicename"] = deviceDB.devicename + end + end + + local wifiType = wifiDeviceDict[mac] + if wifiType ~= nil then + if wifiType.wifiIndex == 1 then + item["type"] = "2.4G" + elseif wifiType.wifiIndex == 2 then + item["type"] = "5G" + end + else + item["type"] = "lan" + end + item["enable"] = false + item["online"] = false + item["ip"] = "null" + item["mac"] = mac + --item["diskaccess"] = false + -- item["netSpeed"] = tostring(dhcpinfo.ip.rx_bytes or 0) + deviceList[#deviceList+1] = item + end + end + end + ]] + --[[ + local str = 0xffdddddd + str = string.format("%u",str) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, str) + require "MZLog".log(3, debug.getinfo(1).currentline) + ]] + require "MZLog".log(3, require"socket".gettime()*1000) + return deviceList +end + +function ww_get_connect_device_list() + local result = get_connect_device_list() + return result +end + +function nw_get_connect_device_list() + luci.http.prepare_content("application/json") + local result = get_connect_device_list() + luci.http.write_json(result) +end + +function nw_set_device_name() + local mac = luci.http.formvalue("mac") + local devicename = luci.http.formvalue("devicename") + set_device_name(mac,devicename) +end + +function set_device_name(mac,devicename) + local code = 0 + local deviceList = {} + local dbfs = require("meizu.dbfs") + + if is_str_nil(mac) or is_str_nil(devicename) then + code = 1502 + else + code = save_device_name(mac,devicename) + end + return code +end + +function save_device_name(mac,name) + local code = 0 + local dbfs = require("meizu.dbfs") + local code = dbfs.updateDeviceNickname(macFormat(mac),name) + if code == 0 then + return true + else + return false + end +end + +function getMacfilterList(mode) + mode = tonumber(mode) + local maclist = {} + local dlist = {} + local uci = require("luci.model.uci").cursor() + if mode == 0 then + maclist = uci:get_list("wireless", "wl0iface0", "maclist") + else + maclist = uci:get_list("wireless", "wl1iface0", "maclist") + end + if #maclist > 0 then + for _, mac in pairs(maclist) do + dlist[macFormat(mac)] = mac + end + end + return dlist +end + +function set_disk_access(mac, enable) + + local result = {} + local code = false + local uci = require("luci.model.uci").cursor() + local dbfs = require("meizu.dbfs") + dbfs.initSmbBanTable() + if is_str_nil(mac) then + return + else + mac = macFormat(mac) + enable = tonumber(enable) + end + if enable == 0 then + local cmd = "samba_ban add "..mac + local smb_ban = "true" + exec_cmd_in_sh(cmd) + dbfs.addSmbBanList(mac, smb_ban) + code = false + else + local cmd = "samba_ban remove "..mac + exec_cmd_in_sh(cmd) + dbfs.deleteSmbBanList(mac) + code = true + end + result["result"] = code + return result +end + +function set_wan_switch(mac, mode, enable) + local result = {} + local code = false + local uci = require("luci.model.uci").cursor() + if is_str_nil(mac) then + return + else + mac = macFormat(mac) + enable = tonumber(enable) + end + uci:set("wireless", "wl0iface0", "macfilter", "deny") + local maclist = uci:get_list("wireless", "wl0iface0", "maclist") + if enable == 0 then + for _, macaddr in ipairs(maclist) do + if mac == macaddr then + code = "same black" + return code + end + end + table.insert(maclist, mac) + code = true + else + local pos = -1 + for i, macaddr in ipairs(maclist) do + if mac == macaddr then + pos = i + end + end + if pos >= 0 then + table.remove(maclist, pos) + code = true + else + code = "same white" + return code + end + end + if #maclist > 0 then + uci:set_list("wireless", "wl0iface0", "maclist", maclist) + else + uci:delete("wireless", "wl0iface0", "maclist") + end + + uci:set("wireless", "wl0iface1", "macfilter", "deny") + local maclist = uci:get_list("wireless", "wl0iface1", "maclist") + if enable == 0 then + for _, macaddr in ipairs(maclist) do + if mac == macaddr then + code = "same black" + return code + end + end + table.insert(maclist, mac) + code = true + else + local pos = -1 + for i, macaddr in ipairs(maclist) do + if mac == macaddr then + pos = i + end + end + if pos >= 0 then + table.remove(maclist, pos) + code = true + else + code = "same white" + return code + end + end + if #maclist > 0 then + uci:set_list("wireless", "wl0iface1", "maclist", maclist) + else + uci:delete("wireless", "wl0iface1", "maclist") + end + + uci:set("wireless", "wl1iface0", "macfilter", "deny") + local maclist = uci:get_list("wireless", "wl1iface0", "maclist") + if enable == 0 then + for _, macaddr in ipairs(maclist) do + if mac == macaddr then + code = "same black" + return code + end + end + table.insert(maclist, mac) + code = true + else + local pos = -1 + for i, macaddr in ipairs(maclist) do + if mac == macaddr then + pos = i + end + end + if pos >= 0 then + table.remove(maclist, pos) + code = true + else + code = "same white" + return code + end + end + if #maclist > 0 then + uci:set_list("wireless", "wl1iface0", "maclist", maclist) + else + uci:delete("wireless", "wl1iface0", "maclist") + end + uci:commit("wireless") + fork_restart_wifi() + result["result"] = code + + return result +end + +function nw_set_wan_switch() + local result = {} + local code = false + local mac = luci.http.formvalue("mac") + local mode = luci.http.formvalue("mode") + local enable = luci.http.formvalue("enable") + + code = set_wan_switch(mac,mode,enable) + result["result"] = code + luci.http.write_json(result) +end + +function nw_set_disk_access() + local result = {} + local code = false + local mac = luci.http.formvalue("mac") + local enable = luci.http.formvalue("enable") + code = set_disk_access(mac,enable) + result["enable"] = enable + luci.http.write_json(result) +end + +function getNetConnect(ip) + local sys = require "luci.sys" + local res = {} + res["bytes"] = 0 + local conn = sys.net.conntrack() + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, conn) + for _, value in pairs(conn) do + if value.src == ip then + res["bytes"] = value.bytes + res["bytes"] + end + end + return res + --[[ + table.sort(conn, function(a,b) + return(a.src < b.src) + end) + local dhcpDevIpDict = getDHCPIpDicts() + for _,ip in pairs(conn) do + if dhcpDevIpDict[ip.src] ~= nil then + dhcpDevIpDict[ip.src].sp = dhcpDevIpDict[ip.src].sp + ip.bytes + + end + end + + return dhcpDevIpDict + ]] +end + +function get_net_device() + local ntm = require "luci.model.network".init() + local dev + local devices = { } + for _, dev in luci.util.vspairs(luci.sys.net.devices()) do + if dev ~= "lo" and not ntm:ignore_interface(dev) then + devices[#devices+1] = dev + end + end + local curdev = luci.dispatcher.context.requestpath + curdev = curdev[#curdev] ~= "bandwidth" and curdev[#curdev] or devices[1] + luci.http.write_json(devices) +end + +function nw_check_sys_password() + local password = luci.http.formvalue("password") + check_sys_password(password) +end + +function check_sys_password(password) + local result={} + if not is_str_nil(password) then + local check = check_sys_pwd(password) + if check then + code = true + else + code = false + end + end + result["result"] = code + luci.http.write_json(result) +end + +function get_wan_type() + local LuciNetwork = require("luci.model.network").init() + local wanNetwork = LuciNetwork:get_network("wan") + local wanDetails = {} + if wanNetwork then + local wanType = wanNetwork:proto() + + if wanType == "static" then + wanDetails["ipaddr"] = wanNetwork:get_option_value("ipaddr") + wanDetails["netmask"] = wanNetwork:get_option_value("netmask") + wanDetails["gateway"] = wanNetwork:get_option_value("gateway") + elseif wanType == "pppoe" then + wanDetails["type"] = "pppoe" + wanDetails["pppoeName"] = wanNetwork:get_option_value("username") + wanDetails["pppoePwd"] = wanNetwork:get_option_value("password") + elseif wanType == "dhcp" then + wanDetails["type"] = "dhcp" + wanDetails["pppoeName"] = "" + wanDetails["pppoePwd"] = "" + end + return wanDetails + else + return nil + end +end + +function ww_get_wan_type() + local result = get_wan_type() + return data_to_json(result) +end + +function nw_get_wan_type() + local result = get_wan_type() + luci.http.write_json(result) +end + +function nw_set_wan_type() + local wan_type = luci.http.formvalue("type") + local pppoe_name = luci.http.formvalue("pppoeName") + local pppoe_pwd = luci.http.formvalue("pppoePwd") + set_wan_type(wan_type, pppoe_name, pppoe_pwd) +end + +function set_wan_type(wan_type, pppoe_name, pppoe_pwd) + local result = {} + local code = true + local needRestartWifi = false + if not is_str_nil(wan_type) then + local succeed + if wan_type == "pppoe" and not is_str_nil(pppoe_name) and not is_str_nil(pppoe_pwd) then + succeed = setWanPPPoE(pppoe_name, pppoe_pwd) + elseif wan_type == "dhcp" then + succeed = setWanDHCP() + end + if not succeed then + code = false + else + needRestartWifi = true + end + end + result["result"] = code + luci.http.write_json(result) + if needRestartWifi then + fork_restart_network() + end + luci.http.close() +end + +function setWanPPPoE(name, password) + local LuciNetwork = require("luci.model.network").init() + local uci = require("luci.model.uci").cursor() + local iface = "wan" + local ifname = getWanEth() + local oldconf = uci:get_all("network", "wan") or {} + local wanrestart = true + if oldconf.username == name and oldconf.password == password then + wanrestart = false + end + local wanNet = LuciNetwork:del_network(iface) + local mtuvalue = 1480 + wanNet = LuciNetwork:add_network( + iface, { + proto ="pppoe", + ifname = ifname, + username = name, + password = password, + mtu = mtuvalue + }) + if wanNet then + LuciNetwork:save("network") + LuciNetwork:commit("network") + if wanrestart then + wanRestart() + end + return true + else + return false + end +end + +function setWanDHCP() + local LuciNetwork = require("luci.model.network").init() + local uci = require("luci.model.uci").cursor() + local oldconf = uci:get_all("network", "wan") or {} + local iface = "wan" + local ifname = getWanEth() + local wanrestart = true + + local wanNet = LuciNetwork:del_network(iface) + if oldconf.proto == "dhcp" then + wanrestart = false + end + local network = { + proto = "dhcp", + ifname = ifname + } + wanNet = LuciNetwork:add_network(iface, network) + if wanNet then + LuciNetwork:save("network") + LuciNetwork:commit("network") + if wanrestart then + wanRestart() + end + return true + else + return false + end +end + +function check_sys_pwd(oldPassword) + local LuciSys = require("luci.sys") + return LuciSys.user.checkpasswd("root", oldPassword) +end + +function getWanEth() + local LuciNetwork = require("luci.model.network").init() + local wanNetwork = LuciNetwork:get_network("wan") + return wanNetwork:get_option_value("ifname") +end + +function wanRestart() + local LuciUtil = require("luci.util") + LuciUtil.exec("env -i /sbin/ifup wan") +end + +function real_time_net_speed() + local res = {} + local cmd = [[luci-bwc -i eth0.2|tail -n 5|sed -e 's#.*\[\s*\(.*\)\s*\].*#\1#']] + local eth02_speed = io.popen(cmd) + local speed_table = {} + for line in eth02_speed:lines() do + table.insert(speed_table, line) + end + eth02_speed:close() + local rx = 0 + local tx = 0 + local speed, tb, rxb, txb + local n = 0 + for k, v in ipairs(speed_table) do + speed = strsplit(v, ',') + if (k == 1) then + tb = tonumber(speed[1]) + rxb = tonumber(speed[2]) + txb = tonumber(speed[4]) + else + n = n + 1 + local tmp + local td + tmp = tonumber(speed[1]) + td = tmp - tb + tb = tmp + + tmp = tonumber(speed[2]) + rx = rx + (tmp - rxb) / td + rxb = tmp + + tmp = tonumber(speed[4]) + tx = tx + (tmp - txb) / td + txb = tmp + end + end + res["rx"] = string.format("%6.2f", rx/n) + res["tx"] = string.format("%6.2f", tx/n) + + return res +end + +function set_smb_switch(smbswitch) + local result = {} + local code = false + local onoff = smbswitch + if (tonumber)(onoff) == 1 then + luci.sys.init.enable("samba") + exec_cmd_in_sh("sleep 1") + if luci.sys.init.enabled("samba") == true then + code = true + else + code = false + end + elseif (tonumber)(onoff) == 0 then + luci.sys.init.disable("samba") + exec_cmd_in_sh("sleep 1") + if luci.sys.init.enabled("samba") == true then + code = false + else + code = true + end + end + + result["result"] = code + return data_to_json(result) + +end + +function get_smb_switch() + local smbswitch = {} + local code = false + code = luci.sys.init.enabled("samba") + smbswitch["smbswitch"] = code + return data_to_json(smbswitch) +end + +function nw_set_smbswitch() + local res = {} + local smbswitch = luci.http.formvalue("smbswitch") + res = set_smb_switch(smbswitch) + luci.http.write(res) +end + +function nw_get_smbswitch() + local res = {} + res = get_smb_switch() + luci.http.write(res) +end + +function make_get_device_details_cmd(mac, patten) + local cmd = [[((wl -i wl0 sta_info ]]..mac..[[ 2>/dev/null| ]] + cmd = cmd..[[grep -E ']]..patten..[[')||]] + cmd = cmd..[[(wl -i wl1 sta_info ]]..mac..[[ 2>/dev/null| ]] + cmd = cmd..[[grep -E ']]..patten..[[')||]] + cmd = cmd..[[(wl -i wl0.1 sta_info ]]..mac..[[ 2>/dev/null| ]] + cmd = cmd..[[grep -E ']]..patten..[['))]] + cmd = cmd..[[|sed -e 's/[^0-9]//g'|awk '{printf $1}']] + return cmd +end + +function get_device_details_duration(mac) + local patten = "in network" + local cmd = make_get_device_details_cmd(mac, patten) + local ret = lue(cmd) + if ret == "" then + ret = "0" + end + + return ret +end + +function get_device_details_tx(mac) + local patten = "tx data bytes" + local cmd = make_get_device_details_cmd(mac, patten) + local ret = lue(cmd) + if ret == "" then + ret = "0" + end + + return ret +end + +function get_device_details_rx(mac) + local patten = "rx data bytes" + local cmd = make_get_device_details_cmd(mac, patten) + local ret = lue(cmd) + if ret == "" then + ret = "0" + end + + return ret +end + +function get_device_details(mac) + local dbfs = require("meizu.dbfs") + dbfs.change_maclist_table() + local item = {} + mac = string.upper(mac) + local sec = 0 + local tx = 0 + local rx = 0 + local smbBanList = {} + dbfs.initSmbBanTable() + smbBanList = dbfs.fetchSmbBanList() + local flag = 0 + if next(smbBanList) ~= nil then + for _, value in pairs(smbBanList) do + if value.mac == mac then + flag = 1 + break + end + end + end + + if flag == 0 then + item["diskaccess"] = true + else + item["diskaccess"] = false + end + + local blacklist0 = getMacfilterList(0) + local black0 = blacklist0[mac] + if black0 ~= nil then + item["enable"] = false + else + item["enable"] = true + end + + local dhcpDeviceDict = getDHCPDict() + local res = dbfs.fetch_all_wire_device() + if #res > 0 then + for k, v in pairs(res) do + v["name"] = "" + for key, value in pairs(dhcpDeviceDict) do + local mac = macFormat(key) + if v.mac == mac then + local dhcpinfo = dhcpDeviceDict[mac] + v["name"] = dhcpinfo.name + --dbfs.saveDeviceInfo(mac, dhcpinfo.name, "", dhcpinfo.ip) + dbfs.updateDeviceOrgname(mac, dhcpinfo.name) + break + end + end + dhcpDeviceDict[v.mac] = v + end + end + + local dhcpinfo = dhcpDeviceDict[mac] + local online = dhcpDeviceDict[mac] + local wifiDeviceDict = getAllWifiConnetDeviceDict() + local wifiType = wifiDeviceDict[mac] + if wifiType ~= nil then + sec = get_device_details_duration(mac) + tx = get_device_details_tx(mac) + rx = get_device_details_rx(mac) + if wifiType.wifiIndex == 1 or wifiType.wifiIndex == 3 then + item["type"] = "2.4G" + elseif wifiType.wifiIndex == 2 then + item["type"] = "5G" + end + elseif wifiType == nil and black0 == nil then + local wireless_res = dbfs.fetch_wireless_device_mac(mac) + if wireless_res == "" and mac ~= "00:00:00:00:00:00" then + item["type"] = "wire" + local ret = getNetConnect(dhcpinfo.ip) + tx = ret.bytes or 0 + else + item["type"] = "unknown" + end + else + item["type"] = "unknown" + end + + if black0 == nil and item["type"] ~= "unknown" then + item["online"] = true + else + item["online"] = false + end + if dhcpinfo then + item["ip"] = dhcpinfo.ip + else + item["ip"] = "" + end + local deviceDBDict = getDeviceInfoFromDB() + local deviceDB = deviceDBDict[mac] + item["devicename"] = "" + if deviceDB ~= nil then + item["devicename"] = deviceDB.orgname + if deviceDB.devicename ~= '' then + item["devicename"] = deviceDB.devicename + end + else + if dhcpinfo then + dbfs.saveDeviceInfo(mac, dhcpinfo.name, "", dhcpinfo.ip) + end + end + + item["mac"] = mac + item["speed"] = 0 + item["time"] = sec + item["upload"] = rx + item["download"] = tx + + return item +end + +function nw_get_device_details() + local mac = luci.http.formvalue("mac") + local res = get_device_details(mac) + luci.http.write_json(res) +end + +function get_wireless_channel() + local res = false + local uci = require("luci.model.uci").cursor() + local channel = uci.get("wireless", "wl0", "channel") + local htmode = uci.get("wireless", "wl0", "htmode") + local extch = 1 + if "auto" == channel then + channel = "0" + end + local mode = string.sub(htmode,3,4) + if "20" == mode then + extch = 0 +end + + local ret = {} + ret["channel"] = channel + ret["extch"] = extch + return ret +end +function nw_get_wireless_channel() + local ret = get_wireless_channel() + luci.http.write_json(ret) +end + +function ww_get_wireless_channel() + local ret = get_wireless_channel() + return cjson.encode(ret) +end + +function set_wireless_channel(channel, extch) + local res = false + local uci = require("luci.model.uci").cursor() + if "0" == channel then + res = uci.set("wireless", "wl0", "channel", "auto") + else + local c = tonumber(channel) + local tab = "+" + local mode = "40" + if c >= 7 and c <= 13 then + tab = "-" + end + if extch == "0" then + mode = "20" + end + local htmode = "HT"..mode..tab + res = uci.set("wireless", "wl0", "channel", channel) + res = uci.set("wireless", "wl0", "htmode", htmode) + end + uci.commit("wireless") + fork_restart_wifi() + + return res +end + +function nw_set_wireless_channel(channel, extch) + local channel = luci.http.formvalue("channel") + local extch = luci.http.formvalue("extch") + local res = set_wireless_channel(channel, extch) + local ret = {} + ret["result"] = res + luci.http.write_json(ret) +end + +function ww_set_wireless_channel(channel, extch) + local res = set_wireless_channel(channel, extch) + local ret = {} + ret["result"] = res + return ret +end + +function ww_get_device_details(mac) + local res = get_device_details(mac) + return res +end + +function get_tx_power_mode(mode) + local res = false + local uci = require("luci.model.uci").cursor() + local txpower = tonumber(uci.get("wireless", "wl0", "txpower")); + local mode = "normal" + if txpower > 15 then + mode = "enhance" + --[[ + [else + [ if txpower < 12 then + [ mode = "green" + [ end + ]] + end + + return mode +end + +function nw_get_tx_power_mode(mode) + local mode = get_tx_power_mode() + local ret = {} + ret["mode"] = mode + luci.http.write_json(ret) +end + +function ww_get_tx_power_mode(mode) + local ret = {} + local mode = get_tx_power_mode(mode) + ret["mode"] = mode + return data_to_json(ret) +end + +function set_tx_power_mode(mode) + local res = false + local uci = require("luci.model.uci").cursor() + if mode == "normal" then + res = uci.set("wireless", "wl0", "txpower", "15") + res = uci.set("wireless", "wl1", "txpower", "15") + else + if mode == "enhance" then + res = uci.set("wireless", "wl0", "txpower", "22") + res = uci.set("wireless", "wl1", "txpower", "22") + end + end + uci.commit("wireless") + + return res +end + +function nw_set_tx_power_mode(mode) + local mode = luci.http.formvalue("mode") + local res = set_tx_power_mode(mode) + local ret = {} + ret["result"] = res + luci.http.write_json(ret) +end + +function ww_set_tx_power_mode(mode) + local ret = {} + local res = set_tx_power_mode(mode) + ret["result"] = res + return ret +end + +function is_wan_connected() + local lu = require("luci.util") + local cmd = "ping -W 2 -c 1 www.baidu.com > /dev/null ;echo -n $?" + local pingresult = lu.exec(cmd) + + local res = {} + if pingresult == "0" then + res["result"] = true + else + res["result"] = false + + end + + return res +end diff --git a/Me_Lua/h10/meizu/r10config.lua b/Me_Lua/h10/meizu/r10config.lua new file mode 100644 index 0000000..e3fdb3c --- /dev/null +++ b/Me_Lua/h10/meizu/r10config.lua @@ -0,0 +1,3 @@ +upgradeFlagFile = "/tmp/upgradeFlagFile" +upgradeLOCK = "/bin/touch "..upgradeFlagFile +upgradeUNLOCK = "/bin/rm "..upgradeFlagFile diff --git a/Me_Lua/h10/meizu/sipfs.lua b/Me_Lua/h10/meizu/sipfs.lua new file mode 100644 index 0000000..21b5f44 --- /dev/null +++ b/Me_Lua/h10/meizu/sipfs.lua @@ -0,0 +1,906 @@ +module("meizu.sipfs", package.seeall) +--sip functions + +local bfs = require "meizu.bfs" +local cjson = require "cjson" +local disk = require "meizu.disk" +local dlfs = require "meizu.dlfs" +local nwfs = require "meizu.nwfs" +local RC = require "meizu.r10config" +local sipfs = require "meizu.sipfs" +local upgdfs = require "meizu.upgdfs" +local dbfs = require "meizu.dbfs" +local btfs = require "meizu.btfs" + +local b64dec = bfs.b64dec +local batchfile_checklist = bfs.batchfile_checklist +local batchfile_compare_upload = bfs.batchfile_compare_upload +local bind_router = bfs.bind_router +local data_to_json = bfs.data_to_json +local exec_cmd_in_sh = bfs.exec_cmd_in_sh +local exec_reboot = bfs.exec_reboot +local findInDir = bfs.findInDir +local get_device_SN = bfs.get_device_SN +local get_device_version = bfs.get_device_version +local get_https_data = bfs.get_https_data +local factory_reset = bfs.factory_reset +local rts_get_access_token = bfs.rts_get_access_token +local set_passwd = bfs.set_passwd +local silent_upgrade = bfs.silent_upgrade +local get_files_list = bfs.get_files_list + +local ww_get_disk_info = disk.ww_get_disk_info + +local get_smb_switch = nwfs.get_smb_switch +local real_time_net_speed = nwfs.real_time_net_speed +local set_device_name = nwfs.set_device_name +local set_disk_access = nwfs.set_disk_access +local set_smb_switch = nwfs.set_smb_switch +local set_wan_switch = nwfs.set_wan_switch +local wifi_settings = nwfs.wifi_settings +local ww_get_connect_device_list = nwfs.ww_get_connect_device_list +local ww_get_device_details = nwfs.ww_get_device_details +local ww_get_wifi_settings = nwfs.ww_get_wifi_settings +local ww_get_tx_power_mode = nwfs.ww_get_tx_power_mode +local ww_set_tx_power_mode = nwfs.ww_set_tx_power_mode +local ww_get_wireless_channel = nwfs.ww_get_wireless_channel +local ww_set_wireless_channel = nwfs.ww_set_wireless_channel + +local ww_scan_ble_switch = btfs.ww_scan_ble_switch +local ww_add_ble_mesh_device = btfs.ww_add_ble_mesh_device +local ww_get_ble_device_list = btfs.ww_get_ble_device_list +local ww_get_ble_device_status = btfs.ww_get_ble_device_status +local ww_set_mesh_device_attr = btfs.ww_set_mesh_device_attr +local ww_get_mesh_device_list = btfs.ww_get_mesh_device_list +local ww_unmesh_all_device = btfs.ww_unmesh_all_device +local ww_set_mesh_network_pwd = btfs.ww_set_mesh_network_pwd +local ww_set_lamp_brightness = btfs.ww_set_lamp_brightness + +local check_upgrade = upgdfs.check_upgrade +local do_upgrade = upgdfs.do_upgrade +local local_upgrade = upgdfs.local_upgrade + +local download_task_operate = dlfs.download_task_operate +local get_active_list = dlfs.get_active_list +local get_history_list = dlfs.get_history_list +local get_pause_list = dlfs.get_pause_list +local remove_download_result = dlfs.remove_download_result +local download_task_start = dlfs.download_task_start +local start_download_intranet = dlfs.start_download_intranet +local ww_thunder_get_bind_code = dlfs.ww_thunder_get_bind_code + +local table_merge = bfs.table_merge + +local delete_access_token = dbfs.delete_access_token + +function sip_get_parameters(commandId) + local url = "https://router.meizu.com/oauth/router/command/routerRequest?" + local https = require("ssl.https") + local access_token = rts_get_access_token() + local newurl = url.."access_token="..access_token + newurl = newurl.."&commandId="..commandId + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, url) + require "MZLog".log(3, debug.getinfo(1).currentline) + local res, code, headers, status = https.request(newurl) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, code) + require "MZLog".log(3, status) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + if code == 401 then + delete_access_token() + access_token = rts_get_access_token() + local newurl = url.."access_token="..access_token + newurl = newurl.."&commandId="..commandId + res, code, headers, status = https.request(newurl) + end + + return res +end + +function sip_response_uploader(cmd, commandId, data, finishstatus) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, data) + if data == nil or data == "" then + return + end + local data = data + if (type(data) == "string") then + data = require("luci.http").urlencode(data) + end + require "MZLog".log(3, debug.getinfo(1).currentline) + local url="https://router.meizu.com/oauth/router/command/updateResponse" + local https = require("ssl.https") + local timemini = os.date("%s") + local access_token = rts_get_access_token() + local pd = init_update_resp_pd(access_token, commandId, data, finishstatus, timemini) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, url) + require "MZLog".log(3, "sip_response_uploader data len:"..string.len(pd)) + require "MZLog".log(3, pd) + local res, code, headers, status = https.request(url, pd) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, code) + require "MZLog".log(3, status) + require "MZLog".log(3, res) + require "MZLog".log(3, debug.getinfo(1).currentline) + if code == 401 then + delete_access_token() + access_token = rts_get_access_token() + pd = init_update_resp_pd(access_token, commandId, data, finishstatus, timemini) + res, code, headers, status = https.request(url, pd) + end + return res +end + +function init_update_resp_pd(access_token, commandId, data, finishstatus, timemini) + local pd = "access_token="..access_token + pd = pd.."&commandId="..commandId + pd = pd.."&commandResponse="..(data or "") + local status = 2 + if finishstatus then + status = finishstatus + end + pd = pd.."&status="..status + pd = pd.."&lastExcuteTime="..timemini + return pd +end + +function download_list_post_process(data, refine_cnt) + local new_data = {} + local jsd = cjson.decode(data) + local nd_msg = {} + if type(jsd) == "table" then + local msg = "" + for k, v in pairs(jsd) do + if k and k == "message" then + msg = v + else + new_data[k] = v + end + end + if type(msg) == "table" and _G.next(msg) ~= nil then + local cnt = 0 + for k, v in pairs(msg) do + if cnt < refine_cnt then + table.insert(nd_msg, v) + cnt = cnt + 1 + end + end + end + if _G.next(nd_msg) ~= nil then + new_data["message"] = nd_msg + else + new_data["message"] = "[]" + end + end + + return nd_msg +end + +function download_task_operate_process(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local gid = jsr.gid + ret = download_task_operate(gid, cmd) + end + end + end + sip_response_uploader(cmd, cmdid, ret) +end + +function ww_exec_reboot(cmd, cmdid) + local ret = {} + ret["result"] = true + sip_response_uploader(cmd, cmdid, data_to_json(ret)) + exec_reboot() +end + +sip_cmd_process_action = { + ["getFilesList"] = function (cmd, cmdid) + local data = sip_get_parameters(cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local jsr = cjson.decode(data) + local value = jsr.value + local path = nil + local start = nil + local count = nil + local IMEI = nil + for k, v in pairs(value) do + if k == "commandRequest" then + require "MZLog".log(3, v) + local jsr = cjson.decode(v) + path = jsr.path + start = jsr.start + count = jsr.count + IMEI = jsr.IMEI + require "MZLog".log(3, path) + require "MZLog".log(3, start) + require "MZLog".log(3, count) + require "MZLog".log(3, IMEI) + end + end + path = string.gsub(path, "router", "mnt") + require "MZLog".log(3, path) + local data = get_files_list(path, start, count, IMEI) + require "MZLog".log(3, data) + --luci.http.write(data) + sip_response_uploader(cmd, cmdid, data) + end, + ["downloadstart"] = function (cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local url_jsr = cjson.decode(v) + local url = url_jsr.url + local dltype = url_jsr.type + require "MZLog".log(3, url) + require "MZLog".log(3, dltype) + ret = download_task_start(url, dltype) + require "MZLog".log(3, ret) + end + end + end + sip_response_uploader(cmd, cmdid, ret) + end, + ["downloadpause"] = function (cmd, cmdid) + download_task_operate_process(cmd, cmdid) + end, + ["downloadunpause"] = function (cmd, cmdid) + download_task_operate_process(cmd, cmdid) + end, + ["downloadremove"] = function (cmd, cmdid) + download_task_operate_process(cmd, cmdid) + end, + ["getPauseList"] = function (cmd, cmdid) + local data = get_pause_list() + --data = download_list_post_process(data, 4) + sip_response_uploader(cmd, cmdid, data) + end, + ["getActiveList"] = function (cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = sip_get_parameters(cmdid) + require "MZLog".log(3, data) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + require "MZLog".log(3, debug.getinfo(1).currentline) + for k, v in pairs(value) do + require "MZLog".log(3, debug.getinfo(1).currentline) + if k == "commandRequest" then + local cr_jsr = cjson.decode(v) + local start = cr_jsr.start + local count = cr_jsr.count + ret = get_active_list(start, count) + end + end + end + sip_response_uploader(cmd, cmdid, ret) + end, + ["getHistoryList"] = function (cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = sip_get_parameters(cmdid) + require "MZLog".log(3, data) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + require "MZLog".log(3, debug.getinfo(1).currentline) + for k, v in pairs(value) do + require "MZLog".log(3, debug.getinfo(1).currentline) + if k == "commandRequest" then + local cr_jsr = cjson.decode(v) + local start = cr_jsr.start + local count = cr_jsr.count + ret = get_history_list(start, count) + end + end + end + sip_response_uploader(cmd, cmdid, ret) + end, + ["thundergetbindcode"] = function (cmd, cmdid) + local data = ww_thunder_get_bind_code() + sip_response_uploader(cmd, cmdid, data) + end, + ["realtimenetspeed"] = function(cmd, cmdid) + local data = data_to_json(real_time_net_speed()) + sip_response_uploader(cmd, cmdid, data, 2) + end, + ["factoryreset"] = function(cmd, cmdid) + local data = '{'..'status:"reset factory ok."'..'}' + local data = factory_reset() + sip_response_uploader(cmd, cmdid, data_to_json(data)) + end, + ["getDeviceList"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = ww_get_connect_device_list() + data = data_to_json(data) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, data) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, data) + end, + ["getwifisettings"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = sip_get_parameters(cmdid) + require "MZLog".log(3, data) + local app_version = nil + local jsr = cjson.decode(data) + local value = jsr.value + for k, v in pairs(value) do + if k == "commandRequest" then + if #v > 1 then + local value = cjson.decode(v) + app_version = value.appVer + end + end + end + + if app_version == nil then + app_version = 0 + end + require "MZLog".log(3, app_version) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = ww_get_wifi_settings(app_version) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, data) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, data) + end, + ["setwifisettings"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + require "MZLog".log(3, debug.getinfo(1).currentline) + + local value = jsr.value + local switch_2g = nil + local switch_5g = nil + local switch_guest = nil + local ssid_2g = nil + local ssid_5g = nil + local ssid_guest = nil + local pwd_2g = nil + local pwd_5g = nil + local pwd_guest = nil + local encry_2g = nil + local encry_5g = nil + local encry_guest = nil + + for k, v in pairs(value) do + if k == "commandRequest" then + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, v) + + require "MZLog".log(3, debug.getinfo(1).currentline) + local value = cjson.decode(v) + require "MZLog".log(3, value) + local base64 = value.base64 + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, base64) + local app_version = value.appVer + if app_version == nil then + app_version = 0 + end + require "MZLog".log(3, app_version) + + if tonumber(app_version) >= 5 then + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, base64) + v = b64dec(base64) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, v) + local jsr = cjson.decode(v) + for key, value in pairs(jsr) do + if value.name == "wl0" then + switch_2g = value.on + ssid_2g = value.ssid + pwd_2g = value.pwd + encry_2g = value.encryption + elseif value.name == "wl1" then + switch_5g = value.on + ssid_5g = value.ssid + pwd_5g = value.pwd + encry_5g = value.encryption + else + switch_guest = value.on + ssid_guest = value.ssid + pwd_guest = value.pwd + encry_guest = value.encryption + end + end + else + local value = cjson.decode(v) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, value) + switch_2g = value.on1 + ssid_2g = value.ssid1 + pwd_2g = value.pwd1 + encry_2g = value.encryption1 + switch_5g = value.on2 + ssid_5g = value.ssid2 + pwd_5g = value.pwd2 + encry_5g = value.encryption2 + switch_guest = value.on3 + ssid_guest = value.ssid3 + pwd_guest = value.pwd3 + encry_guest = value.encryption3 + end + end + end + local data = wifi_settings(switch_2g, ssid_2g, pwd_2g, encry_2g, switch_5g, ssid_5g, pwd_5g, encry_5g, switch_guest, ssid_guest, pwd_guest, encry_guest) + + require "MZLog".log(3, debug.getinfo(1).currentline) + data = cjson.encode(data) + require "MZLog".log(3, data) + sip_response_uploader(cmd, cmdid, data) + end, + ["checkRouterUpdate"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = check_upgrade() + require "MZLog".log(3, data) + sip_response_uploader(cmd, cmdid, data) + end, + ["executeRouterUpdate"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = do_upgrade() + if data ~= "" then + require "MZLog".log(3, data) + sip_response_uploader(cmd, cmdid, data) + end + end, + ["setDeviceName"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local mac = nil + local devicename = nil + + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + mac = jsr.mac + devicename = jsr.devicename + end + end + + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = set_device_name(mac, devicename) + require "MZLog".log(3, data) + sip_response_uploader(cmd, cmdid, data) + end, + ["setWanSwitch"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local mac = nil + local mode = nil + local enable = nil + local value = jsr.value + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + mac = jsr.mac + mode = jsr.mode + enable = jsr.enable + end + end + local data = set_wan_switch(mac, mode, enable) + data = data_to_json(data) + require "MZLog".log(3, data) + sip_response_uploader(cmd, cmdid, data) + end, + ["setDiskAccess"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local mac = nil + local enable = nil + local value = jsr.value + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + mac = jsr.mac + enable = jsr.enable + end + end + local data = set_disk_access(mac, enable) + require "MZLog".log(3, data) + data = data_to_json(data) + sip_response_uploader(cmd, cmdid, data) + end, + ["getSmbSwitch"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = get_smb_switch() + require "MZLog".log(3, data) + sip_response_uploader(cmd, cmdid, data) + end, + ["setSmbSwitch"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local smbswitch = nil + local value = jsr.value + + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + smbswitch = jsr.smbswitch + end + end + local data = set_smb_switch(smbswitch) + require "MZLog".log(3, data) + sip_response_uploader(cmd, cmdid, data) + end, + ["setReboot"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + ww_exec_reboot(cmd, cmdid) + end, + ["getdevicedetails"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + ret = data_to_json(ww_get_device_details(mac)) + end + end + end + sip_response_uploader(cmd, cmdid, ret) + end, + ["getDiskInfo"] = function(cmd, cmdid) + local data = ww_get_disk_info() + data = data_to_json(data) + sip_response_uploader(cmd, cmdid, data) + end, + ["getsysinfo"] = function(cmd, cmdid) + local data = require "meizu.bfs".sysinfo() + data = data_to_json(data) + sip_response_uploader(cmd, cmdid, data) + end, + ["gettxpowermode"] = function(cmd, cmdid) + local ret = ww_get_tx_power_mode() + sip_response_uploader(cmd, cmdid, ret) + end, + ["settxpowermode"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mode = jsr.mode + ret = data_to_json(ww_set_tx_power_mode(mode)) + end + end + end + sip_response_uploader(cmd, cmdid, ret) + end, + ["getWirelessChannel"] = function(cmd, cmdid) + local ret = ww_get_wireless_channel() + sip_response_uploader(cmd, cmdid, ret) + end, + ["setWirelessChannel"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local channel = jsr.channel + ret = data_to_json(ww_set_wireless_channel(channel)) + end + end + end + end, + + ["scanBleSwitch"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local status = jsr.status + ret = ww_scan_ble_switch(status) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["getBleDeviceList"] = function(cmd, cmdid) + local data = ww_get_ble_device_list() + require "MZLog".log(3, data) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, data) + end, + ["addMeshDevice"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + ret = ww_add_ble_mesh_device(mac) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["getMeshDeviceDetail"] = function(cmd, cmdid) + require "MZLog".log(3, debug.getinfo(1).currentline) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, value) + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, mac) + require "MZLog".log(3, debug.getinfo(1).currentline) + ret = ww_get_ble_device_status(mac) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["removeblefrommesh"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + ret = ww_remove_ble_from_mesh(mac) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["getMeshDeviceList"] = function(cmd, cmdid) + local data = ww_get_mesh_device_list() + require "MZLog".log(3, data) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, data) + end, + ["setMeshDeviceAttr"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + local key = jsr.key + local value = jsr.value + ret = ww_set_mesh_device_attr(mac, key, value) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["rebootmeshdevice"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + ret = ww_reboot_mesh_device(mac) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["unmeshalldevice"] = function(cmd, cmdid) + local data = ww_unmesh_all_device() + require "MZLog".log(3, data) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, data) + end, + ["setmeshdevicetimer"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + local timer_id = jsr.timerId + local flag = jsr.flag + local start = jsr.start + local ends = jsr.ends + ret = ww_set_mesh_device_timer(mac, timer_id, flag, start, ends) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["setMeshNetWorkPassword"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local old_key = jsr.oldkey + local new_key = jsr.newkey + ret = ww_set_mesh_network_pwd(old_key, new_key) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["setLampBrightness"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + local timer_id = jsr.timerId + local flag = jsr.flag + local start = jsr.start + local ends = jsr.ends + ret = ww_set_lamp_brightness(mac, timer_id, flag, start, ends) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, + ["delmeshdevicetimer"] = function(cmd, cmdid) + local data = sip_get_parameters(cmdid) + local jsr = cjson.decode(data) + local value = jsr.value + local ret = "" + if (jsr.code) == "200" then + for k, v in pairs(value) do + if k == "commandRequest" then + local jsr = cjson.decode(v) + local mac = jsr.mac + local timer_id = jsr.timerId + ret = ww_del_mesh_device_timer(mac, timer_id) + end + end + end + require "MZLog".log(3, ret) + require "MZLog".log(3, debug.getinfo(1).currentline) + sip_response_uploader(cmd, cmdid, ret) + end, +} + +--"{ \"size\": \"14.12MB\", \"version\": \"1.0.10\" }" +function OTA_process_action(vs_info) + require "MZLog".log(3, "get OTA new Version:") + require "MZLog".log(3, vs_info) + require "meizu.upgdfs".push_new_version_msg() +end + +--sip data format: +--{ "push_event": [ { "appid": "com.meizu.router", "data": { "business": "1", "commandId": "54", "type": "realtimenetspeed" } } ] } +--post d = '{"business":"1","commandId":"53","type":"speed"}' +function sip() + local ret; + --local data = '{"business":"1","commandId":"53","type":"speed"}' + local data = luci.http.formvalue("d") + require "MZLog".log(3, data) + if data ~= nil then + local data = b64dec(data) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, data) + require "MZLog".log(3, debug.getinfo(1).currentline) + local jsr = cjson.decode(data) + if jsr.type ~= nil then + ret = sip_cmd_process_action[jsr.type](jsr.type, jsr.commandId) + else + if jsr["com.meizu.router"] ~= nil then + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, "OTA push message:") + require "MZLog".log(3, data) + require "MZLog".log(3, debug.getinfo(1).currentline) + OTA_process_action(jsr["com.meizu.router"]) + end + end + end + luci.http.write_json("sip done.") +end + +function pysip() + local ret; + local cmd = luci.http.formvalue("cmd") + local commandId = luci.http.formvalue("commandId") + if cmd ~= nil then + ret = sip_cmd_process_action[cmd](cmd, commandId) + end + luci.http.write_json("pysip: "..cmd.." "..commandId.." done.") + luci.http.close() +end + +function upload_router_log(logdata, logtype) + local https = require("ssl.https") + local url="https://router.meizu.com/oauth/router/upLog" + local access_token = rts_get_access_token() + local pd = init_upload_router_log_pd(access_token, logtype, logdata) + local res, code, headers, status = https.request(url, pd) + if code == 401 then + delete_access_token() + access_token = rts_get_access_token() + pd = init_upload_router_log_pd(access_token, logtype, logdata) + res, code, headers, status = https.request(url, pd) + end + return res, code, headers, status +end + +function init_upload_router_log_pd(access_token, logtype, logdata) + local pd = "access_token="..access_token + if logtype then + pd = pd.."&type="..logtype + else + pd = pd.."&type=".."4" + end + pd = pd.."&content="..(logdata or "") + return pd +end diff --git a/Me_Lua/h10/meizu/upgdfs.lua b/Me_Lua/h10/meizu/upgdfs.lua new file mode 100644 index 0000000..11559ff --- /dev/null +++ b/Me_Lua/h10/meizu/upgdfs.lua @@ -0,0 +1,256 @@ +module("meizu.upgdfs", package.seeall) + +local cjson = require "cjson" +local bfs = require "meizu.bfs" +local sipfs = require "meizu.sipfs" + +local b64dec = bfs.b64dec +local batchfile_checklist = bfs.batchfile_checklist +local batchfile_compare_upload = bfs.batchfile_compare_upload +local bind_router = bfs.bind_router +local cal_str_md5 = bfs.cal_str_md5 +local data_to_json = bfs.data_to_json +local exec_cmd_in_sh = bfs.exec_cmd_in_sh +local exec_reboot = bfs.exec_reboot +local findInDir = bfs.findInDir +local get_device_SN = bfs.get_device_SN +local get_device_version = bfs.get_device_version +local get_https_data = bfs.get_https_data +local rts_get_access_token = bfs.rts_get_access_token +local set_passwd = bfs.set_passwd +local silent_upgrade = bfs.silent_upgrade +local table_merge = bfs.table_merge + +function upgrade_lock() + return os.execute(RC.upgrade_lock) +end + +function upgrade_unlock() + return os.execute(RC.upgrade_unlock) +end + +function push_new_version_msg() + --type:4 (有新固件更新) + --msg = "{\"size\": \"14.12MB\", \"version\": \"1.0.10\" }" + local logtype = 4 + local msg = check_upgrade() + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, "OTA push_new_version_msg:"..data) + require "MZLog".log(3, debug.getinfo(1).currentline) + sipfs.upload_router_log(msg, logtype) +end + +function push_fw_upgrading_msg(url) + local logtype = 6 + local msg = {} + msg["code"] = 2005 + msg["result"] = "upgrading...." + msg = data_to_json(msg) + local res, code, headers, status = sipfs.upload_router_log(msg, logtype) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, res) + require "MZLog".log(3, code) + require "MZLog".log(3, headers) + require "MZLog".log(3, status) + require "MZLog".log(3, debug.getinfo(1).currentline) +end + +function push_upgrade_finish_msg() + --(5) type:5 (固件更新完成) + local logtype = 5 + local msg = {} + --"content": "{ \"version\": \"5.0\", \"size\": \"14088999\" }" + msg["version"] = get_device_version() + msg["size"] = 0 + msg = data_to_json(msg) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, "push_upgrade_finish_msg:"..msg) + require "MZLog".log(3, debug.getinfo(1).currentline) + local res, code, headers, status = sipfs.upload_router_log(msg, logtype) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, res) + require "MZLog".log(3, code) + require "MZLog".log(3, headers) + require "MZLog".log(3, status) + require "MZLog".log(3, debug.getinfo(1).currentline) +end + +function subscribe_auto_upgrade() + local http = require("socket.http") + local url = "http://u.meizu.com/api/v1/upgrade/subscribe" + local serviceCode = "com.meizu.router" + local pd = "serviceCode="..serviceCode + local sn = get_device_SN() + local sipToken = sn.."100032" + pd = pd.."&sipToken="..sipToken + local device = sn + pd = pd.."&device="..device + local version = get_device_version() + pd = pd.."&version="..version + local deviceModel = "R10" + pd = pd.."&deviceModel="..deviceModel + local key = "2635881a7ab0593849fe89e685fc56cd" + local toSignStr = serviceCode..sipToken..version..key + require "MZLog".log(3, url) + require "MZLog".log(3, pd) + pd = pd.."&sign="..cal_str_md5(toSignStr) + local res, code, headers, status = http.request(url, pd) + + require "MZLog".log(3, res, code, headers, status) + return res, code, headers, status +end + +function gen_check_fw_url_pd() + local serviceCode = "com.meizu.router" + local pd = "serviceCode="..serviceCode + local sn = get_device_SN() + local device = sn + pd = pd.."&device="..device + local deviceModel = "R10" + pd = pd.."&deviceModel="..deviceModel + local root = "true" + pd = pd.."&root="..root + local version = get_device_version() + pd = pd.."&version="..version + local key = "2635881a7ab0593849fe89e685fc56cd" + local toSignStr = serviceCode..device..deviceModel..root..version..key + pd = pd.."&sign="..cal_str_md5(toSignStr) + + return pd +end + +function check_upgrade() + local ret = {} + local http = require("socket.http") + local url = "http://u.meizu.com/api/v1/upgrade/check/router" + local pd = gen_check_fw_url_pd() + local res, code, headers, status = http.request(url, pd) + require "MZLog".log(3, debug.getinfo(1).currentline) + require "MZLog".log(3, pd) + require "MZLog".log(3, debug.getinfo(1).currentline) + if res == nil then + require "MZLog".log(3, "get "..url.." failed!") + ret["code"] = code; + return data_to_json(ret) + else + return res; + end +end + +function do_upgrade() + local ret = {} + local http = require("socket.http") + local url = "http://u.meizu.com/api/v1/upgrade/check/router" + local serviceCode = "com.meizu.router" + local pd = gen_check_fw_url_pd() + local res, code, headers, status = http.request(url, pd) + if res == nil then + require "MZLog".log(3, "do_upgrade get "..url.." failed!") + ret["result"] = code; + return data_to_json(ret) + end + local data = cjson.decode(res) + local value = data.value + local digest = "" + local filesize = 0 + local upgrade_url = "" + if (data.code) == 200 then + for k,v in pairs(value) do + if k == "size" then + filesize = v + end + if k == "url" then + upgrade_url = v + end + if k == "digest" then + digest = v + end + if k == "version" then + version = v + end + end + end + if upgrade_url ~= "" then + require "MZLog".log(3, upgrade_urogtype) + push_fw_upgrading_msg(upgrade_url) + local ota_img = "/tmp/ota.trx" + local cmd = "wget '"..upgrade_url.."' -O "..ota_img..[[;]] + cmd = cmd..[[nvram set upgrading=1;nvram commit;]] + cmd = cmd..[[killall dropbear uhttpd; sleep 1;]] + cmd = cmd..[[/sbin/sysupgrade -v ]]..ota_img..[[|tee -a /tmp/ota.log;]] + ret = exec_cmd_in_sh(cmd) + --to do : add UCI set upgrade flag . + end +end + +function check_mandatory_upgrade() + local ret = {} + local http = require("socket.http") + local url = "http://u.meizu.com/api/v1/upgrade/check/router" + local pd = gen_check_fw_url_pd() + local res, code, headers, status = http.request(url, pd) + local upgrade_url = "" + local flag = false + if code == 200 then + local data = cjson.decode(res) + local value = data.value + if (data.code) == 200 then + for k, v in pairs(value) do + if k == "url" then + upgrade_url = v + end + if k == "mandatoryClear" and v == true then + flag = true + end + end + if flag then + do_upgrade() + end + end + end +end + +function local_upgrade() + local fd = nil + local nixio = require "nixio" + local image = "/tmp/ota.trx" + local touchcmd = "touch "..image + exec_cmd_in_sh(touchcmd) + local function image_supported() + return ( 0 == os.execute( + ". /lib/functions.sh; " .. + "include /lib/upgrade; " .. + "platform_check_image %q >/dev/null" + % image + )) + end + luci.http.setfilehandler( + function(field, chunk, eof) + if not fd then + fd = nixio.open(image, "w") + end + fd:write(chunk) + if eof and fd then + fd:close() + fd = nil + end + end + ) + local clean = (luci.http.formvalue("clean") == "1") and "-n" or "" + if image_supported() then + local lue = require"luci.util".exec + local cmd = [[nvram set upgrading=1;nvram commit;]] + lue(cmd) + luci.http.write("updating") + exec_cmd_in_sh("killall dropbear uhttpd; sleep 1; /sbin/sysupgrade -v %s %q" %{ clean, image }) + luci.http.write("update finished!") + else + luci.http.write("image_supported check failed!") + end +end + +--push_new_version_msg("test") +--subscribe_auto_upgrade() +--local res = check_upgrade() +--print(res) +--do_upgrade() diff --git a/Me_Lua/h10/mime.lua b/Me_Lua/h10/mime.lua new file mode 100644 index 0000000..f559150 --- /dev/null +++ b/Me_Lua/h10/mime.lua @@ -0,0 +1,90 @@ +----------------------------------------------------------------------------- +-- MIME support for the Lua language. +-- Author: Diego Nehab +-- Conforming to RFCs 2045-2049 +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local ltn12 = require("ltn12") +local mime = require("mime.core") +local io = require("io") +local string = require("string") +local _M = mime + +-- encode, decode and wrap algorithm tables +local encodet, decodet, wrapt = {},{},{} + +_M.encodet = encodet +_M.decodet = decodet +_M.wrapt = wrapt + +-- creates a function that chooses a filter by name from a given table +local function choose(table) + return function(name, opt1, opt2) + if base.type(name) ~= "string" then + name, opt1, opt2 = "default", name, opt1 + end + local f = table[name or "nil"] + if not f then + base.error("unknown key (" .. base.tostring(name) .. ")", 3) + else return f(opt1, opt2) end + end +end + +-- define the encoding filters +encodet['base64'] = function() + return ltn12.filter.cycle(_M.b64, "") +end + +encodet['quoted-printable'] = function(mode) + return ltn12.filter.cycle(_M.qp, "", + (mode == "binary") and "=0D=0A" or "\r\n") +end + +-- define the decoding filters +decodet['base64'] = function() + return ltn12.filter.cycle(_M.unb64, "") +end + +decodet['quoted-printable'] = function() + return ltn12.filter.cycle(_M.unqp, "") +end + +local function format(chunk) + if chunk then + if chunk == "" then return "''" + else return string.len(chunk) end + else return "nil" end +end + +-- define the line-wrap filters +wrapt['text'] = function(length) + length = length or 76 + return ltn12.filter.cycle(_M.wrp, length, length) +end +wrapt['base64'] = wrapt['text'] +wrapt['default'] = wrapt['text'] + +wrapt['quoted-printable'] = function() + return ltn12.filter.cycle(_M.qpwrp, 76, 76) +end + +-- function that choose the encoding, decoding or wrap algorithm +_M.encode = choose(encodet) +_M.decode = choose(decodet) +_M.wrap = choose(wrapt) + +-- define the end-of-line normalization filter +function _M.normalize(marker) + return ltn12.filter.cycle(_M.eol, 0, marker) +end + +-- high level stuffing filter +function _M.stuff() + return ltn12.filter.cycle(_M.dot, 2) +end + +return _M \ No newline at end of file diff --git a/Me_Lua/h10/mime.so.1.0.3 b/Me_Lua/h10/mime.so.1.0.3 new file mode 100644 index 0000000000000000000000000000000000000000..022ab118d8ecb6370bdabae29b332142c4388897 GIT binary patch literal 84630 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 YT!<(a@WyCeNk#o@yh079Q(9*IKb!DUMF0Q* literal 0 HcmV?d00001 diff --git a/Me_Lua/h10/mime/core.so b/Me_Lua/h10/mime/core.so new file mode 100644 index 0000000000000000000000000000000000000000..022ab118d8ecb6370bdabae29b332142c4388897 GIT binary patch literal 84630 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 YT!<(a@WyCeNk#o@yh079Q(9*IKb!DUMF0Q* literal 0 HcmV?d00001 diff --git a/Me_Lua/h10/posix.so b/Me_Lua/h10/posix.so new file mode 100644 index 0000000000000000000000000000000000000000..21d530bcd9435ad2ed4e8eff88410cd75ea65c61 GIT binary patch literal 34716 zcmeI5eVCP1x&NO%FE|dPj(|x>xm8e97&bU6Ddt875FKR8i!X)F3^N;;n3wI$9$q|@ zgP@|JkmAefVC)LZj0!ts=E1_Gj&-o`MCK{1d0_%4D?E{*QSmtj=emBs z|ITw=Yk%*1t$W?;Ua!x3*7NMO?wD3NJr;`v;guhZ3B>Im9R%fIq9zFPf}pTGhzA9P zjR;OR;i0^6_s!N7ifIo_xbgch{Bef~IEowO!qFG3TY%ed-C=k+g%{wi@5$Bye{+T5 zYY2G^Hw||$?l#=5I9&+~!G#W&gCu3HGx+@&ZY6G&@v%Q20Pe!ITQ=ATPQh(*yr2R1 zFfJeW2rj%Ha6}v&hHJtt!(EBfH3T;mcQI}*?o&Abx*cW_ZWOK=HwHHwcL(m1xHg=w zkKj(lrE$05blqnmI0+n%TkrS~QV`eU7USOUJnwWE!aqTndI3L*TZe1Kjm3?}sUoUz z3vuD~A&3nj6T!3LYjN+xUG9Z7LNCEB#Z}_2z}=5~6n7nN4KBPYAkKBnwGJP0_#n6f zcb4P-f5OQqr`ZOj|3D%iM5f5e4FyLyy4c|<4&Mt3@GS8HCVI3;^+R2!SunqoJlZEG z`;13l;L-0z&T^iYc!4uKdOGw?xO1G}eDK4#t8g=MH{;&xx)IOQab>s@acAP@;LgV- zaTno6m3=JN&rAtiy5OCvdBA8QcjtT~)XVxOrl@?zRxz z;4p;CAlBmU!PSSJ?}4k78LoU+^Lzd)>PdXz1h8M2*?~kPawTQic^5m8N;}QP9 zJpBqk5YhJ`FI?$85F^3^u;6g zJQWGw>XnD$AHs!~_*5kRV_tqWkGKJTB!m7sZvI1p;^3bn`cCzD+4Bd_e(@8%aHaR@ zi2is)ezYgA`1>OHnTlU{oelABME^1L6v@KSi%OJDrXNc>a1^c3D5;pc?PK-o7j zV$T@Qe#IXf3IAqedUiZSKe@Y}jKZ@}CJYM=f8Hv9Szwna2TO#)K zc=1hmgg-4J|G7x{PxaDM`kx6C1EueFPoKhHB);FCKkw<6d}oB8?eU8LN~F9>BK7gJ zi2gC2ebPVE(X45V6W=(Bq zZc5LqS=f-aVecJMRlA}_3ThhaZ%+peZ8cSyw$>#Lt=X3Prp5hyeN#5QINj3EM}nK` z8-l8;bW2N9b5%ogZB4emxhX&fpXPx`i@aEi)7fluM*1qNYL}#Imxd{{rn3#riyLcN zmj<;B&8=w|Pb##lb!BURKyxM=MqXZ1pUu?QVM|TAW?_9*{lo#fZesoIRud7L+8P&< zowjU!V>)OvsVVE(l^NKkhWe(ZK{mUxsfN%{S6yBGvVe4Jo0}H(mxI%zxV0_mnru32 z%3C}caXB<(=2xNb&{`Vm8>w=XJIa{d zys){sAzee6uWU5Nw=~w(w***JXIKd}rI)w0rd#T2vNa}Ilr5@HH`EyheT~>YV7(f_ zvYLjrfhJL_>S$}R9>^aTc~QD)S+Jwa8Rskg3ToF-6z7bW#1H=Adz@ zEL>XO(4cHBX>QF@Z>rZN_SP&ip=7wg*B~d6IC{-AGI0IIO=s(hLDIP}Y*15Mn{IW@*L3JM)6y2zV^edGX{MeR zEoz`u1&dl&Hq{1oZ5g?V!6KDtb8FC;ZltOSwQQ!It{C>cHg#lWyD?*6$-tlzwtTdx z4Fa{xmD}d!^alJ?ol>bP0Uc}F5UlfUC9thY;;5h)R4!E*RlmX(LpXE>4fP96p_a8a zmnFn4uC1+V6*s|zS$~GYre*al^zW*)DTS)4g{`es^yC&s>jAo|%5k&=Lpub58B?cL zT~wwOviH8cTUo!rd-?ST_7mPstKZKO|5*Gm((%&AYYoFf4CDMQO5*sqe=Fnrgc|*L zF;7E`r>1u9ySiWMnt$#}mPGP`{qEkZwO6gZyyQ^p6XN$e+~@E$hx;8KaCpe!n+^{< zJmT=E!($GEpIiL}4vQR?IvnP3xWkbS;|@nT9OH1T!-T_04ktTII;?PbwZlq>DTg;X zT;Q!OAhxs+~@E$hx;9NI6UC+ki$0}9(H)d;ZcXj90tE|_35z4VTr?1hr=8WcR12v z+~FvPV;qikm~dF`aFWBx4wDWm9A53P(qYQsJcl&yJ@J)w@9UgIb)ZsCQ!G2f&4vQR?I4pHI%;9i{BOS&aj&eB0;aG9E4#)eb8irX0?5c$32g4yzs3Ib7nf!C}T>*5L|=s~m1;{Xpa8W8i5lP;M4- zo5~5VWW7>2CkUPtvWUD*Sk2n;>%9Nq`DLAu=bZII#^jAc)>}3Sd0Ft7kVWy$LS7W) zgpA-@g)ERgDdZ)@HX$z%whI~TcL-U;c~;27)J`EU9d-$avDPc(Wx-2AGO$O;3!=Tk z_p|mQ91#Ss3D4kNpKxRlbO=AdTA+{@8i#~u2Em)cIBOQdvx4A=@NC}c3C{_FW5Q7s z)Gxu&yu%Zo%li=FdA!>Yj^REfWFcjkkQWleg%`38CFF%uTsV$*VM1OQj1lq@YOFB9 zyFDQb_~pWhK`=?k3xvtS@*qeGFAahUAumX-7Ji8LO~T7q6BAy}`oC~8?=yr~@P1JE zVcv5IldP2pr|`Z?copydgj0E!Agl<2tZ*9dp@h>}OA^lD{h^Q-8Eb_zsed6aFV+jM zrT&H2QUAi()W0xA{R^+B{)Mc8Zxzm?{)N0~*(RiYZ5Q51{R?>+^Q`b@>RR-5k z`WN0p{R?lU{)IKvzi=V-FRZ2hg>}@wFirgn7g7Jh#niuW3H2|mr~ZW>qyB|UsefSu z^)GCs{%Qa3Yoh*z&D6i}HtJv4Lj4O{sefUX`WLoQ|H5U|zi>JAFI++W3s+MA!rQ5T z;XhIT!d2A2@Z;3K@DtR(@DA!<*iQWmS5yDOJE?!+8tPxTmiiaoMg0r!rv8QZQ2)Yv zsej>p)W7hP)W490udMI^>R-5l`WJ4b{)L~S{)G=w|H4hwzwlw|U-$_1FMKozPTH00 zJp8M1Zxn2=>^l6lGu|lZ7}rzKv8Ctajtw0}hrivk|9Q&v`y09j|8RZR{=e+(3F&d-P6^-r>>PJbJ4~Z}#X-9=+b9*Lw6SkIs5@gGbkS^a78b=h2lOUE$G_J-XbZ z$9nWAj~?mK!#ujgqYFIx*s+1~JmS%Bdh`L0-tW=-JbI5u@Al}O9=*e(w|VqdkKXLj zn>>2GN3ZqhRUV!7=mw9j^XLU0J

nJ-Wi9Cwp|cN00UBQ64?gqlbBPiANWB^szsC z>2GN3ZqhRUV!7=mw9j^XLU0 zJ

nJ-Wi9Cwp|cN00UBQ64?gqlbBPiANWB^s#rn^7rUBJ^Fx0@Av3^9=*q-cYE|s zkKW3bc09NdGrF0p6Ah(9$n$llRdiJqsMymD32cL z(Zf8t#G?y5`q(>O`Fr%69(};0_j~j{kKW_ayFGd*ba{MBPkFGVCojICBaztB!&e9$ z`SClu^5WGU`H2l3gMvBTAM6|dso}`wB_2A+7fRw|L;J>ezVt2T6Sx)MW&vmw|6T3d+A$+t}HHrzH;K zvqv`Zbx3zn`}4zPduS8l#bc1k54Ic}-q-h=mvAFxLp;}Q;>2Is?d;9u&6QmRD%60cu1>HgXm7W&T7#GYLO8opFo*T+kbwrTZ*dv+YU0Zre;=;YD;lyLc)*UNd-E|7OWFxwajVgcT=Tu}$ z;&~mxu8p+)^?J3{8+2@>Uh_Kg;y>zC9hmTVdk?cgV@p1BvE`)AEZCHP%we9xAjld2 zjXbBENqZ^|uJ4Y$wP9l|x>O&uq2BXwV{qr=F2G%gL!5F9ddqM;!t~a4($*8X?$Y>! zl;QndYGbL62fEh0@IXhwuFX9q!H~{1FZ}ZKal3N)`MX{?7)z|7jm%XYkH{N5#FSq$ z7}7mAk;`vQkCeR@kuAMBxidIPWo90t_bzWRNw_9})gD(a1 z;HiV+L7>`33>*sP6F!W(sVlYP2Y$T^98J95d5)&d^j11rHdZ*AdhVUUXU34b9t$kiiu_0o2GRR&5&Wukg5#tp`) z+(Z|-@=$rs_)DKDN70&ixHB+U-5#{hkDMzFQ0ZgiSc6^jW8D6 zrhYRb58bcRwl&_4KqiKa#>>M~uq#P_t|ope*Im$_>ue@G$mBXt2Qn}7=;E!G1 zDig-wZt1%lzhTO2d?246aq*R>8gxpB;`~DX3Cc@4;t$bgbDfXN58WeGF4!c$uiz&v zg#X1c(!>_&8Y(^U4#p8{!vm6|KgyOy>2dK@hSci_`0n-Gcg~`2et@2W#N$181Vg)5 zm2N3Se{2x<67Grm2DrF2-uLTR{Hm_MGR9Ju_orEpca+Au)UH|+ zzyI|e^z&Gd8%mrJs&mCT!NvJ1aSBUcH-29tebsXj?Yxw{e1}f?Ib0j=Ps&#{WlH!r zkyCzDUdpHHXq@tvv1PMY;R;K^$0?(Ptw+_%MC2}&ozA}?xW6ag>9`R81g?nkDhkf( zIf=450o^(Lu$Q)I_1sE%m0;sxY}A;kv}D&+$no`WPf|!ZDxb11Khe=SH*x4-khs6+ zTEb#M#*8Pnj%lCB{Y5sT|0L)l)pL+i{S+%~Cvnc9Ecx24Cl#QFG#Jl2&&9u;`Ad*c zTY0>Pv9()sp*5$rcNCOd`EvQec{*PrCW6_zHq;4`BI)cQbl*L@rmh+JPrP2)Uq3q{(7jhq)NV$=> zUX6K-<-IH)_OdicS#Ii?j_mdX<%cfm)SQc(aBl%&R}%JEBuwLa5n+=EYmbEK-cv%@ z1j3d?!ZiMt5_SP$sYn=KAoh&HpZ3gL$mUypdcWrvjzMQKE+1a~{GmNxV{HakjjO^OEEcjHqs{g40L*Sqa(*1cxfwrk3>nmCzUXT1IK zo>3bg@A)io)J`e45sD|9HakD=x5f{h-Sqv=fB!T6!IYbodl0!o+As4o(|!xleTr_~9VpoRFZM#ciLu4Z9RS%)4|*MtYjj5v#tt>-Xp>PNh3y!ChU_r8)Jey|cPX zl8l)tEBkq5HBVPN9ZBCSM8C#$mGSW4{zIjNiGGT4VHEvA^W3_>^!3gAB6D`aPC%#P z786f$8V7;|HiE-k+~LfJKJCU8-Q(x|wXbhD@vqi>2w9Em(xJAhd(moal5UM@8pAXv zQocg{!=2s=^sYs3IHpdc-t~>yt}h&K8{^yGwXFdit)6W=Y0#^PulwLN*b&|bGw{`v zov{;rMJdV(I-tCQhmJ1Sfc)^GPZS`>mKav8AJJoWwahUuE&mQ z$~Z$AFJTZn@&xOzUfKK<{mXG-oewkV*)gO~V+i(y_T>mu`RRVCbYFze7f-#1e&5FL zi4EKX?qFO_JZkbVn0Bgrg!26(!h_OO*Sz?aZ=mC8>Sp^XLGT=_usjz%ej0Vnki&g8 zr7`=)ZrxK#ic=-y8pDz=+LueXtV0~dz6XBR`vHU$N4W1?x>efwebw`to_(b z*(wi9@k^%Am7y(|wvp@HA{*(Cg{ci4l<{e}!V|C~Kk@KEjV%|^FQhL_|0rX`6O1(r zo@DKso6s0s{~Skh$z134(n&dO0t@3_A0zG~#8q2RImdoJ%gj9_TY+rs0`51YEqmuk z2XWPxVnK@;!_^*^kav>omE0E;hq8+O+}8Qgsp#EEUR6&?`a(Nn8Z!G_KiQih?Z z<=(CPFmoQ$@6?A(c@m~EME8!}%psPV_%`3VcO>7XZb!QLDmub3>1E{lP7O@oxsJRP z#*c3kr;?7D<9cy+d2!Bpk2nP`PMF3okw1m_s^2`D*p=#%UfOc8%Kht%mAe1Ml9U^A@4RE@+xa|`P;vJ$Ui6%BR)vjo z>O%*2prZge=};Tdb4m?XBk8TAs@WBB|>8}6mz|L*gj>X)>8w_!^W zxE&6q~|}?k^15*_^bU~10R;J+QZIwn8&q0f9O(gYiib`qj}qg z-;21{u#^7TJ3Ep$%G%`Z6Ucnog{ht5uTSNBces2mB~0b@E#%HseqGs^_Ew$iUPSnM zjX^GtYS%X+t2jaF!#!s?TJxu0A*;2Dd{4I0g%=?^!=)wJeb6O|hkFLm9yLeP7$co0 zAs>#1rfo8pdJfq?xOtiG&+C~?-$a{S&Uh8J%W7okd;NV>ZK#+&x|4jWZ~5h^{xw5( zkyn+8(tVito78`+Ew6kQBBT1J?G*FeYQ|iZgTmfNScCIZy7IdU9nz)zZHAWp;`5=^ z*M4@?>f@hu_8vlAX#SGH))$yN$I(Z*8(rfSKfrGCd&~P-kHIa&?WVJkb#u?wz4&V4 zoPlhRWIYz!S)c2Yy)pUGALwhQ?S9DcclXGSqv+K0=it)2x}J9F$WQLK+zT}SQXeT) zoB+KV_t81V@OCX^Q)KK?J5{;9Wzu0zue@@vGv(ps^B(f4HWo|a; z!dPM2!C=-a??YE1GSXq%0`v7t@%wK#P8C4guxVY}iJ#}ntB^&{qq7-PDNB_}Y`fx< zUMAOV%fUWx2gHxHw|4~_xj(M9e!5Q%!C(0aa=27`&xyf}>NiitGWT@JR?Tsw`&^U$ zQ$1QwRvRm7U)zx%e6+J5QDn+lV>4q&ah38$-})@_imy69I{W!U%v*Y8*H085d<9h5 zYku`lvVn5vndrIvL}?dT9MgKo;K0;r*e)vq+HAo4Z|Y8dj7`OQhcV!1>uZ$fH`1er zdGtH9ul?^s0q&c)ui#9-VXjr==HKDmyC6QT>(}IKUV=7z0qYv9&#SES6AvEL`X%k| zvdQsqo{}^3l#e5?IgZ-k8t6Z%T;NrQr;y(m^{4rmo+;GskMR&S8ymv45S~Z6zUsxv zb8*780>6)|e!h)t9%U&y?APB?{8X;Fc`^D`Pux?A6|Oe&UB(jDeS3$q)>2I#RYnWq z@g9vKlBFz*6O^UorC^Y1|Qudog@ zuX$ecF!lexQ|I->`JdEzfP7fzgP{Kd7pC_hw8}JE=O1NJFt#h#sd_2Jmb?TuCV9TW zR@Kqh|I}ZvrtN5~|Mj2xde0}G)*jTS%vh*;Pv*KOlaBgSk@$_aZg0i!G0HS(XYP>O z!dkv9TlHg=?{^3<&M{xjB)ej%KhdA&Yc0Mw4aSpe8PfZxKfQCBuXhc_wO}6p+^6K< z+XP<(PZKWAKr_e6e-m2i6sw-d%lCNZ)cYIF&(#jFuX8Esst&bg@Czn&`*4RD%cj3R ztINzaGr7(aJtuxjp67O7L!L*2dQUO=vs-$mpLBm$JZSGKPHa5L zdlrpvm#P1*BHr{55XQJ&ocPqiSbR-aaeVc`!W=fm(ZxH*i?JyN9n0O-)x=uwD0DKe z-ZvVWb(Z2r5M8murFZA?SW>L{NGpEa=8Kns^3%J>xVxt{mEPS&^X}cs7!=x-AD3No zH2*VpX)RBR37r<*jajKSAJ>x!I<)!_^x@^qx_6R_gLa-?kZmQg?Fhd z(O)A>Yx*k3!T8Um9%HHdx}J97FVjBNuBX3#KXt~l_6FAZsmI^b$&b(=%zFgtNn?g7 zYue~T#4+u$n)cW}(AUHEc!q3gckMB*_BhA9D^htBxc106L3^BI+T$Ydh--_>q186E zZngqiZISnzX8cjU&cS}YPgEOJ`+VhX`fS{e3#Kjdp5mL##~&pRV|Y=e@j-USlDsc4 zdCh2CEK+>QKaF3Yd%xrLoT72ybezV|t>`!7nhU256f3=-D4rZ+UQw`-s_n>^d=dRr zb0pI*-|p+(&q9di>E^l5*`ct%NN+;VM!|?lgv%D$pm9y%+ld<_9y0BkcN)XBHWHQD zhs+lAAEd5gH2PNMm3*qdbW%=vs<&$NqB|v9NuPhK_q+ma`jlPAGtYoKN?-0gT{5a? z>`p#O*H)?Dj55qXVmH&OQeV>s!3N3z6`{8vp`Zt78)-y+(jrF<#h zGl_fHr87+TD&l=Dl8;Zi`p}xJ^70vURmqR}BlC%;4tV#+({+DzeL`iiS+*cYKN&&O z?p3-k^UR}rD7Kh9e^Jk|*v+)8mtA3cR-5!5=~=71W|R;7L=#7S>THE)QeE`nr@}e5 z#{HwTABF2(SSVYFtf>>$HB`RkPPd-9jUIcieM;{?RMw@GPtwRdY~I7X3>^z{-FgRl zxSjU_OtejaG8r?MC*6F_QT07W!2MV4s#*E7_vsP(=0kSK-aW=%)*q3T zpYGR^uXXaeSLBg)xQ6-+6Ze-H2(QHT*EcpiL;5C`-CfZ*+#z@VV)H!%Zn&WqM0?#4?BIDPZhW|hleR6wI$Pj zlDW<)Mkb?ox<&Gn9n)kJeK_P*mz(hWGEQw~l1n=b*LYnR&vh;)e76e=$7{)Jybj0Q zxqs~I9g7X-o zM`t*Oepfodd%1&dOv-KxR1KVVm>X)Iy%n6=A=b`w4Jg>9-+ZezvrQyxtD z(3j~4KcPMUJoNvH(Xp`$|DoZt&n2N=?30|z{26T1{Gfs``APOa$wLhLbf4ZldP~pd z({!(9e5uAB#yX8F%Ey%PcXoZ1c=#!qtUM>C;QE?jeX zg+GH|@?xt?`Tw0Ke+BdyC(kp3k$(!m;hub#CqDr?i0Jx>|TlU|LU(S>F^Lr9u>zsU;-`nvkq+Sc+c8;cTEG(ZG^a3Xz z+S7zzrKkT3p8OxFv+{`iLc&LR@}KtP-$1@3B7Xzn$1WNup9eho*O5Ok^!W0*hVXr! z{GFcsE6DGR$bXpdZJzuxPyTzzZ;HrIBz&zW|1nSgTgW#=7M+<$R8PE%O|YgJi-r594ODrJo$T(-xHC48^4{N ze3>Wzal*Db`LI3o;8H+JN5YT{3?F23HBQvjSs)}*NPJ`yatC>&gGflm7tp0w*7q|9$vXdh*}(D+ z4K*#=DI#5)ZEjh~z6dofHQF#DUYA~0Uz-jVvR%v4kZFZx3x+F$(XE%oN4ILf1a^lo zyQ8F6)MwLmX1@-gm7Ps8V43z?_?s$ISSWnx;B!SW~sQma18PVNi2nkZo>`vzN`{ps6_f!kyS-_eA%#78fSk2d>pG}f@u1Upm2 z>s#Y?-;II&D9pwai|R7X?4@D1fLNApY1L*e)=D;gXsKyg8E0FMcx78n{Nl0+@$vC% zYMSB`6NyPdGM*?>)L5^Y*^*&sZ%Nw z#?O!w2FQs6Z-q zRBP9?S<~j&uql<(=FBrvQ|HXI#I!k9`o<}9uA6zC6}xWsyqQy{8M&F)O`mOuifLEP zpAl{l(!ckJ-H;^QoJ8Aoxa~^Zb|&HWCT3S5vm1)}$%Na?xSd4=t!_^dv(t*(0c2o5 zki{*{>@@=4zd=i;rnQw#Lhv%X#Ave_w*igWkH&6Ihr<3|rn*EAY3 zd%HG&F{Ih{M3Fz%ys(PRda^Ce4MA(ovUFWleI0wduq~32L!_#EKkjAEyyM)O;1e$7ry zwRV4|TJ{DaINeZ_Y1QDfByBbgs%6s{vyY3}nZSS zxG&?j<96Vl!+i^8ieQKxQ%YXYk*O>wwmE zFYzA0J&1c0_c-ne+&0|TanIm%%}2hXf`5pB2a@bd2krouf<@qM;G}CwAKZK;Hh@|1 zF7WV&*((_=x`K6W?B6k+FNoo{kLBxA@Fv0^15@B16YaNHgNmp*aEJAe-_*b z|2$ZI4doARn#r64Tyh!jLBOlQ*TKw(Sf2$)UBrJ9NOw1Se+OSViM1`T1bi2K=~DLn zB%k}rx#z)ef-i)x21~$~CI-P@h<|7X`w+mlUmOG<1XJKB@bEP1RsNOigA1;w94%pz#+3#0!U^Td;j9HQRt85$GJC6TM!yl#G zZUb{u*mE0ffNuvEfJLNx>_RHcUAnioa6=ciJA42vf!DsEEESmjVc!pGUmMo80?iFr z3o-lK=o+keG#!_=vl#mCIJZvOf4i^?u4o2c2?MH3Q8skfN47LGtDKmaP+pdpG%mqaK5p^E@`>r1OBbFWFE5)^c9989lqV*{$M`y?&|?F$ z&tMQc8?x}yaZ`dp#V1TDik+A@q+nR=wAktS!($`z&W??Z1!Zi_$M$+)w#DL-kXlm1 zu4rX-E1M9pm~9El7B{t(g)>i|sUnPgNZt||X2NA=%eJy?dIhxE4zjGJ*-RSB(o3oq zwP+(lBU4q=(o(b1%7nD!jLMc~lYC8MeJ$xXqsppa^Rl3t+@kSFF3UJ0URO9)odvBiN&XtATq47yhavHDBcf8~@uE}XU z3ongDx+dT>Hc3w7l3aqoFkPV>w=gr7iPm@~7l&4w(xr5D&B9@hiKFpQPUB&yPjVU; zHGK%>G=9oyT$P;sL%Aww>DRcdaa~UN3$HNUkKhr?h5aI>NbZuHTpAb3>C6hbm$?6g zSEz5PC%1L3y_dXKy0(%+H$7i5&K>S+&hdyw<@+6{F-Nx00GobEO27I3d}JkVbsPeX_L zbU$2i3-|f3a-E!XKI6%04BAdbhG`MhPw#|Qdr-PNklTTr`0xtjynu(&O}GHbnRN)q zD@^W(ICN#4cW`cX5O~#VWE7_RwbBf)xz)T72pLeibP2ue1xXrE^>BMW##@BRzEYgp ztgkQkapo)XbXTY^@2Gve1?+U`Ql%LCZKmWe|dX!fI=NN?ZLn~5b=8Njz_8R=2 z^6OmrsAVetc2C~s$i@!!hvlbPq~@C;p9eo4e)zdoUg6R=#^aeX_w%9r5-(iw!}8E9 zQ}OjIXRqR5n#YIn_jutSC0ymF_84OpD}7=8Xhiv#$H(BMU(bv7DmLfQgnX!9!6j`l0^B`C$xOUgaLYmmu+b$WSQ1|AOP? z`w#b_ykAw&g*>YOlJ5lT;8!?a_Pz#hFPq+ekN*t;;^Uy=zYXfSq}uU{f74ig%w^;2 z`6cA@uv5HRzT%g_>p7>w@ru9AlP`hS^Q66sgJH;vzZwt4KLcLRO|Lm#@ptzRcs6}K zU)ifTI1734kKv*CW8n2XCOgC{envm$vhnrY7V_hf6Q96C@|VKv`A#N^Pr~noALZ%W zFJW_8eMdZg26EyY8ui~HqdGXv1`{jpUG!VXw@Uc8km%DIduNU4F2}39 z_sDp2+49nQLCAjvdGV|82+OPD;(>6br}YAR6$k%{y!fy_pM%%B!c7P${%-i!;ETXe z-=0eb;=hc42YjWImwxf~vh8yLbA;KX4UbTM@?`_zlGnP9 zy@~^!10g<+hvZL&*ZPn8X&8U)o z1Ms7qyuQI%2fx7a(l6d#w){IhUg3%#hF?N_t%v3C2<_bpZ!c@_lOBIL^5UO#@>Aip zUZ$Ce;$H)=b+nMzeW4nDqYGDk?bpMJxvYMz%Z2>S$ctZ#M`%yOl>_0jU+a1HDh?JR zFFx!qOX0Qd*MLA6zaZ(vUHKPzd<*j8w;>YBZ}-BL-VTpniM;r*zqG?2fcNdKo`1_C-uO=6!x7iCxD~xoyY6hMf?&^{(u)Qd97R8 zt2p=p^5Vnx{9|~nzm7#f>HQ2|>#u6U;&twh)^W?d{C2QDYA>5#t(S&;H}c}!@d)i- zaJ36|?L+In_9_nEKwf-kkJ|4pFI@I(J=b2v!CT0S--}16f8ET1aLH?(*j~lKG33SX z!6THv>6(FX$!mStUW_+9Qiz|2M<~DD3zz&3pGRK2Uti_dI(06;S}(U3^9|(1hx&ES zht`pgAP}avs&YVH>1n;$Ud2HIdGVX^2<3Op836zPJCBY=w2cNt(y!-cdzA*a5H5Z=9x?99b?^t^t-jKr5x(^2p}x{! zIs7E}xRd_`{7vxc?~1<`Ui*TF;Tzz!-?z1=G8!9{(o#!fOb`kqH0i2%o2nx=ZpWM)*@bzLfB@ zBm8)eSNuyO{ABo@u6%Xw-Hb^1brF7kg#T!Sua5AGBYd;R%ii_~zcIq+;KS!toqP8M zFI@R~%HyT)*$Dsr2yed~L6A%FU-!brABga8M)GZ9{U zfP|OiU-bAm{IB4(2C7Tv-t~ClO8>COEB@ONzAwVtZ;qtR*8fR^EFJR0BK!v;{J9bS zLXVd{mwUYInHu4*iSYiKt>Q26!o@duy!5q1_}e4=9Uiav>m&SUJYM>~=)*$FZ+HF;a~H3#n)yW z;U&H|!XNf{>3b)_4=M^{+h^(_5&p~wKQ6-C?*gq3r9Z<97k@pxU!GNw@JxiiJHoGz z@S7t1r#)Wzd&=XL{@p#E!9^t2YyyUNg_sf5NBz&RAOW#tDSNz-I{q}sf7cTkxBmCz*Uh$vy zc*%b&!ta9j^?xrCzCXfuMff*7Ug`bOWjlB-cXLJ<0LeDDxT+CRaMtqrGv(58mj8}II^{>rj5_0nj13>oC8%?Hfhqu6Zj7C zJ%r48d-mli2R&u^tkS$-t*UElY+Okck244K9Vgmgz9Pg_eYjZF$mdW?g6ZayvFZ9A z&3>7t)7R_~UZUIyTPg2z%vAp;Vk!5{Sjv7UmondzrR;}ODf^*W%6)d03O_@euJ5T@ zN!ER&R;P3J_(D`4Ii_rw)SBbkQvDymP4A~t?#nq@JhLJ|wyBn19aNXH-@wUM_g!ep zoIsbdU(KcZzoJvd%m-|ZE8PikDfh)4sH4hK=3Bg!`!FwMj)XG_+aeNaKj;%>zwt|% z4**m4lR$LnBT_1r`qDRoDQV^VGo7y%r1YDyU_J#k-;qkh9EFw&4^>Oqj}lY%J4L{l z*8dSBU!dBLOv~z9TWUBGEERsrN1^Mbd&-@Q*0@qu@{M5QN_*a+$$QFtL}(1=OSqIh z87-xw(Ng9!)Ra3?Pgx9$6H=#?$xA1l8O5Ax#{2oE)+`?bX39PkV5dH)R4wScM4{p+ zkJL2pudfZO_uBqSz1Af#*EWE;p~T#NiMb?6b|VIs2+9l~uE+PoFz&Ue&xQS5;2aIcRmQ%~kzh z|8jbzi>LBbnY)s3hvShUbCR1o?$DfEXHK2-&Q;71IepEZvxdKS{+lg) zQ|zwJ!jtLHt|J@=j_#9(X}|ik@jXt-vr zUY`u&xIvYcInU4@&S)Be62!m%C`fm>r9Jx3*k`KFP~Mq*G{yhxX{F)$gVL=tG~MZ! zjMd>8koJg0GeXc#^{H(C@qNU}ET`|8&s9wY_$Ob6{aTsg6hYgqm5mm6(xhnBZFsJr z?f+7$$}#;_B2-2HVVN%1$DI(V_BL<~ATi9hwf1}RFg`g84=hE$`IMEQ$|~Bh`z}5_ zMzDX>4C_gUnR*q4HK-=R;|_Dh*Y!+l!Hh;OWpi3*m{fRns&_7-J@oLnV_A)~cQZn_ zF<5!5Q}@>Cv*BI#xU*-&al|`iwg0$M*(0T{A5jXLDF25Ae*R=MtA+_l2O(HWfsg=6&hpC#IVt}E55&X0or ac;-;nfr$3DN&4H2Z#_c$^n8z1Uz6=RIE`@QBlK-mMSd?BtSGIry(d-t+7(Y z4jDp4i*1x+%Z#?AQ`*uFZLy72TiRmFSf}GSwoP(41(CM2r7dl#{662c*G@J^oatQ8 z@42q$k0%%V+-t4-UiaI&*X!P!eg9Q+ul7981b;cE$|zSk)|hJG=JTQ^VoYweiJK_6 z@j&6jf0ZABo-0>{9mcP(vWRD|hCE|da`DgN;b+>xw}aPpki0J8qg?Yc?G1o;`~~=W zFn4if6WvMK2eWG3?DDO^DIwe~q~9CLHk_Urx%5}YbsE=1 zW%!f*bGTZ#in%W2(qALjDw{IqRtHxDujaarYpN@o@1VeJm#zVx!*wp#6o%@;`%^pq-~1c-cQDHd(F`YD;PU06awUhk{OMWc%8ubGa^>TJXSnn<2Lliz zQ5s~j;HBhexUvZjjs{k`bOLxe*JQ2>xNN@w>hChH5jJJaT;O?J*K*y!wSa3B*Cejs z??w_AbDhn#I4A@zbm^ObXK^j#s^D6|^**i-aOrOmm-^F8uJ>^1?|iQ1HucV*xR~&l znCjm(O(kE zi{F&2{IF0!i2l_qc@Jgb71R6g=7+!G^xzFy^dqwJw`J*jQx?80#9#Vdiao)f@?BZ= zD?)hb`}>eR%6~D7|B|fynk@QX1j2xl_scAKFJ$4@X5rrsC9D1`0TL+uxGZ_ILill{3$yIkoVF6gF5qxRt$Oh5 zL;Yo4mVWa?{G@+QmcB2Az zm;9Ak`K?*>zskaYJd6JmS@zu>qL=)!S@^E3_PHzz|Jf}5tFrw4=MaDC9}n?UeohvC zTb4aP3*n{T8Cm$FS@~ljeZ+rcmb~v~>HkPp{l*ZzJu81rR{eXj;&Evf{XJRwKNzYn{W77vH{O%CF_@%P^H8qRgENNp|P!TMbql`#hD_Jh_XxS z8|#-gEooS`D%pH;c10*Vz3D>(q)pQs2GR|y*DM{(tXk77-cIF~HLI4QaZ7zm>+0sl z#^fMfL(`punfitXBa50=HMTBqsK484CmURS%dj=so|SDLG;!{d`ZjzcGXrzhNJ;ss zY4u>eCGD+)8K-23jdfg0Q}Y0mhUsfUX3Ik>T$3zavs{hb?puomAvSX@pSH%;Yw)L3 zkS%xCH?Q$qr>!yBT))imNs<#UzhUPtX=%J`RbzX7yNwdnUDnoE-%g35Cg8PfS##^^ zHLkH~Ll+AQi<2wMs{=LL?@szGnpO{b4v(x^-PqQEM6)_c$h0rFV%l3n23Z4^hbqB$ zc~fJv?_gQCw6(RlvA)Ikh7H#>mZdaC!IQNj@L=GJL8q4bRlZ*BtpOXVD5hz11xAo; zY9YvzG@-GndZkc`RZoK*`}SEzOR}C5OY4&6)@AkWP3UFoSw~=m3ZPClHnv$~Q5yf674=O^Nc!Bt z%T9|AVpsv!_(79wZEiNJn^rI+nAMHVjmz4N-{Z}))|M7!+ZvbMY3i3PYs6uz8(SLe zPkXB^U*6Wb%G}k~)ZR$8zQHVC*3#Z=6hVzmV$>n4{ypw8bt?rpCng29z>F?&V z?=BYi&2A3Y*^c(2RSs$&sC>e~Y6oXHIMcxz2WLAt$HBP{);hS*!9@-(cCgOD1_xI< zSit5`@=F{nb1?2;rGr%tPIfTi;7kW=9Gvao90wOVxX8i94%Ru?;NVIJn;lF#*zVw3 z2iG~c-oXtHZgy~sgDD5MIryxD+a28H;BE)^IJnoreGb0n;2RG1I=J7#gAN{c@R)Tyw|}F2iG~c-oXtHb~(7&!7UDUJD75Cn}g3fxZS}W4(@btmxH?< z>~Zi#2lqI**TH=bzUts>4!+@FuY>y?Jm}zI2ah;-)WKs89(T~>yY_Xkz`+s+%N?w6 zFz#Tbg9!(#9h~9dOb2TmobBKo2j@Ci>)=8M7dg1t!8!*U985ac?%-Mn?{%=l!F3L< zcW{G)T@G$`aEpW84yGL3=HRmqZg+5pgF7AE<=}1ydmMbx!95P{b#R}9uR8degKs$4 z>)?I|k2rYL!D9{{chIo!*Z3E8u)x6*2V)MFIauysg@bViD;=zIaI%952df>N;owXM zYaE>I;2a0%I#}!ALI)Q)xY)ru2OAt*>0q;iNe9~JsF}z-B=v z$1Q>!D0d68DNG4+fV)kw%$R2dxk<2HkVEVpf;7}l!E(-S1UZP_Eyy8pk06K6FA8$j zx<`;34toVT$lWK%A@!?*absQ+9Ba%Qg5!+o6&%kwrXYvH2L&e@b6AiY2S)@ss5vUg zLGm%dbB#GJr~~OJa0)<>8xsYB972}}CRh&$au{AFI30fra$sB`$jyPcAj_pnL2iIl z30}lmw;=735ahtRT98BM8G;;o&lKbUx<-)0@!5h`aAqQSC1>G+v$@wHcopZ{f>(2X zEqD!Q--2_vPa$|M_l5+oqx}W1r~L&vP)`bSnBFeP;rUuY4$1Eotfl=0=h6Ox9JsF+ z1M;LSR-1>QpY3%-~37hFX93v#fY667Y&HbHKXJS(`E_7~(P%nm^g-**Zwq5TEx zbd~_Dr~L(&(*A-Cw7*~@?Jvlo{64`Iw7(!Xd|ng0o%R>JgZ39}ru_w1(f)!hw7(z+ zhDQWHNc#)6(f)#~X@9|X+Mj+iat-Y-cqeDLJ*mDUznJo7bjRHOBVRn@&1mnGOtg1v zW=QYG-hw0F%2XVn&UZKV5Bb4{{)#{C&IIYQP`V_Pj)v05|2Rm0G?YFZO79P)-w35& z4W;*n(l3V6yF=-nq4f4pdRr*n9ZGKwr8k7q>q6;!L+SQVx;d0?2&ET?(hEcBxuNvz zP55RgER-$@rK6$r@jrz8A4(q%rT2%@Z-mmXhSGaO=@&!k-J$f( zP%sF-5g3cgwl&c>4l;6+)#RUC_OWjt`4Oqhtidy zbVVp#7D|_d($P@*_|cI6L+Qhz^!`x#jZpg4PeLg|uFIvPqJ z|9!~+q4eQUdOzvv_|{Cd*_w&OH})nHTQi&t_vXYu(jSS}_2wit_U4)S>9bCpx2YVu zNa9gO#0AQGBTk&xw~*XiuCji{e74*(;4>rU^QeZG7u(qD#e6ncQ=96GnpEF^yiM9P_IjqKzh`Jq-wa19{LQw0Z8{gap~j5vi1|J^gZe5v7nrQs znu*qI?2Xo}>n})b-mmiW@ntkohVK`o|9s-aXb&C4cMkPUB9)$vo${spa34J6W7Shx zl>FpS-Z)v2SZ{hP>3(eMVlLmn4bwPqE^So?jBzEMjj??<^e>QI_)79*vxhyOR#{zb zKTEsO!kxH$Xj(qVjivf}&bul7i)pjd4_JTHrdcKyMW*$p=a|le1vQ=hw8x=>_>-BE z1Q%tc)QeJY6gsieN&g8uWBWS$lh`Sr8`GJIa{UH<#b0u^TluNJrM_-`UcxUIek)~- zmzAWY*URYfHu)6SiHj+#>&$%e(pl*oQ;T0aUwZw-i60z*Z^BG@^R=3n`;NqW`i|A~ z^d-!52Z_bLeO`}ZvM+%@O7MkrHMIRO$u&=At`w}1>?bqw%X`RoR2Nv;Q<43$@Ns+= z(l3{?66{N0-;pb(yeU2RA=7lg8y^RLyjFGb2g}CML78YpW95Ql={EYcx;=eCc^>-Z zkLp@Ur2iqVwcHygcYma9f@BgVizUt^s)gF&K z99y|}w8!NkeFL9=7kcSCU-bfgozEY1y#6cX^Vi;`ZMz(8=ERAjaGUIfK1QEY-x`Db zBi@U)-^b`PLAf1!{j2?_;`VhBYzB^{WJCe;!j_a{zopq zKCRe~P)B~>gkJ69A-uCoZIuIFy#64)6Zotjo zGUbWQnRw#C{+yb1y{6`)nef=Fu}?k-d>)H+AhRP=k?5daN2Y+QgzIbg_K110Prldu zD4k2pCOannNVdlZ+v$1o1?I8Lo~-h3lHaDj9Dk{AY8GxM`5b(uxzDy6zOejhv#*6{ zj&Bff4E`UyTZx$VWO>JoBuNr?G5l(auh4=)0 zA&0Uf=6lvp;r4x)@`3ifY08_Gv>h?t=XIp|_8wRKq|)(tCv*L{jC3wzj?>)zONYZ} z#O18C>GI=FxVOOlD!|vUM8Jh+1= zK#BE-znqtRn6%1ge+OND;?<;n5@Sx}`u9BZ-oE_0)R*$i!amya1;&=wW6ak%W?k>C zAsE+0! z2s!DB9i9Do@do0OepWO;U6JTi{Ej!YVKnwguSs=giWAt{^NEaNx+G+E$L`9l^qH&s z6?6lyo5jg?Gc_aYZ89ph@_|*oRvX+=}-b*d{+Qf{s#wt z@8B3i|` zMQN7ZMFq6u&rY29dWg`*;|CX z9ORbus1Jeb>C6;KcKk`!i>baZ;zw^ZxZbATs@Mbl-X)#=x$#X0su=5vW19|0N7)-O zALxtprp6A5f!J5*yfDgLlPU&F3ks4nf zV>~tMCX{m(nnisj@pT!F);`ITZ)w(-MJ2UQW+Z1AK8P{as{KwCXXW7KcaQb?KcIus zn_XEBW#^J+{d35p4V!602K%CV;09v+$krj&M<=%4ls=5#|l0GUM zX`3J}6em$^J+aY`my()PpJJknxG{JbOi_W-u~#xh zW?q`(*doOnV;{0R`@PtM{fYCe}3$h$39Bib@Z0RKdN=k_=?y^Cs1bn&3IIli~aIn9Xx_`d7Su7Jkno59G4K= zk@$n!FZY$xJ~@d8dP`Ur&{xM-B#33Mt*)+oAYQ*Fzm2ow9?p@saaCN;IXLT&3e!b9 z&9`e1kN#lS42%;)Ovjt1rz4}hXOd~{B{T+*_afxAFRw7HvCPI^(UgVKC86{j&b6z# zc5%+F{h(;=x`_6UV5e7?>Ql^Y5AAiYB9C9vYI851>U-`lC*JA`;V%O(ociJ=q_rnj z{x(~0Gdj&}houL;(mG@hdaI9WPd`+8 zI3D+-gVF|mXIb90tYb`3cZfd6(T@PqHt_fNo%e=l{^IyZuiHaBZz3%n4iQhj%vAb5 z%4Sm+AM|N2ES(lR8PY?(sUlw)&?NlvMRYe%m$Cg&0(&dC_Fu#O0j~92_DluZBju%b zy&a)#PmE#ALe4!-C++Qj?9%d8mrKjHzZxj-P0zr$pTf6CPM#6oXo`RckI|ZCQohq6uu9fGz5qQRht)Z?#o_uciVbIF&9}n5~LGi<0l|OBH*DCI8K8h{xceL`AVr&?4 z7FoJfI*EPqiTq)Z>m`wm+&8qptMPpyzF}YF#|M4U4ZVtLelE|yW#+p>$_t7!N8YbE+ z8zyJubHkXgb(?sa+RlTVS-e%|V)Vb`^#Nq#tN)STb0K~S{2{$6Yo5$V55;ZRCx-P; z9KS?+CtKefg}?6`^9`Nh8EiGo9nvp>KNRcBolpGnj`b~dj0E_kA6TKiSCgZyHsqcK#mZT(!wJP0rG#w&;v>bb)P`Erab+*O|$uU5KM}KlUg_bw(;)L0fzPUhF^n#{r z3i@LNy$j-gpHv^zSyBmk#hc2)=>dFJFk z>QUFt$#xu+k2D`WtGcX9HU4Prq`nT{Lj|#&c0ESENaM*3qC@5}{1s(CrG38UKFv+} zG5?-PFehn#kZng#QQn6=vx-F{Iy4 zHY6UtqJ7f0zs(tTjPo^@|2%o6hk{!c!YRLvJacTCHc2mbxFG+et5*o_=1@K5A9uK1 z(l@#^V@>*c(u#u^>DyeL82J`_sPf^I2fT)pUrD*zcpT+39et3$&+!@oj`LY-lXxh9 zC;5chgLnw$O~u_Ze3Cte{Pj;Kk0Cnue>F6=ULily?m4kk`b*F%t$tWbxz-ShpJ%iB z%pT~1zB(1U4e(1QPVhP*{ewNF#(;A}d_NW9JBxC~D11jR%HsRw5M3K|8gmM;H`#OI zmpSpyUd{cIp?hO$(^7EiYx}S%m_O@?)!95ZRL-+R1wi%Pa^^kG?)nuM1wFJkb+z}^ zc`*07G65g?&{MyS)%MdjhjCCg8d}?5S3BKe%&)sh&v3eHZ=i7}-`QIRelhrpEc^+| z;F&IGywjXqPRthQ#b9(9iyc4yo4+nsUTx~t`E8;;|15Qr_}H$slGrcZYqam)*jo!u z{?u3-g^!6np3zt!yG#ui{Nj}B%vC-*g6w?Z84rHw>KQyj>io4{!fT#FyO zxq>m!BsTeDUJtTrG>#*KIyuyhBa8O$SDPr7q*p#`M2&xnL+Gq8w~_YD;Mk`&jpM)Y zT2V0*3DF$nP-i^+rxN>>z{x<(`QO8DrvYCAs(sZ*Mq@AM+P2Rr-AFpDf3%0ViMh2^ zOn$fNwk=Rbm8 zE$cU+#`ZF7)jXiQ>D`c-UE7&?Nql$I_Dc>iRP-(K#iYL(vU3Jy5hH!!xz9h_)LCY6 zJk|GwKe7(&(pvX@c8#~VqqDyvg>N}aFEdYM;ys)<_vlTxThg)E6B)1Cq*)VaUxT|l zGX*=eo<$G%h(}1CgRHsSH{V`=#IA=pk5u>=7=lJ>JittLS>d>d;FpmlJO% zEI-ckc>cK2jWi~-!e6?ifOArc2B3Um;x?T5I)_53iwrF4{WIOPwJo6pyl|1;@8kEGI0kHaB7j$HBF!KOd5r^WBhjNkXl z|MZt(Kf9q{&l%W$LjUmUu(gK0uK3dr67+*g;(rLXQ~@hpKZv`2pqLNhJ`R3z9s2|H zG|9o(SIlT^JRTkF<9Ac0*dO*Y#x)oF@>hO5)%WW^oOml8+WDO*~hV*x1WCYo;i*v3C);!Y-Z@qKv+onM+=2-N)e!^iUCNwLI*Se{@#QxH-C0 zJ|bVioRSOf5tmmx#+7#Th0uF-5A{Fb@aiAehiFd=rH7NQsC~@pd^S3JJ-Wa4SSH5Y zYWro9`I|o45$k-j7yC3eXzU;cM!!rx9Al3;zQI`VIq=cMW0?rH{J^!T=0n+atD`L^ zFTHOG>GUh=ao_2XY<-GyjXzJ4kJFD!$(b~Ymjef9yCtItY7&1^!vz5PSr_Lj~)lFYxdllBySIua_E?uu{4IsM6w zHJ=r)1alH&S2Qs;!`U~_Rn_vmjplpKB@*11(?wsiIwMQ`e@H#SDE|HtYZ~btJX@pk z+1MwWaznBHEoWaqcPf28nx&7UkCk>SySG8mG-Nx z?dQat zjx6Zt%={Jk^7m=9zn#mmvld?BTNL-7qxgY%yEynd^bzJ}`C~l&y@)ig6BKQUZOyRP zOUtjTp)UacD)D*bK|elsizj70Azl}fRvd-tzD(JBMS~yi4YlRDS+w?fJ10-{lBehF z%F!e0%ICRq&Rq{x;md8)c`p6Dzu%|dmv88I=lm~y`p?d%%&P-Fm7nD^os}H>JA63K z=^pmY9hAw3t-zo?GM3lLKCB0yCmMWsZpeqPXVHdzDEd?R(71B>a6gA`bzD1mh(Ix~ zab&v3I8?*=caAv};VeOYJksl*JDhIgV_rG}RG+CP9uma1=^_3Sj6cMn##GKFGZl<^ zTIcKRaHx6oU~qmo)T}!=Bw^Q@{S~yU?4JzHIOHCUn76__BaTjc@Y#$l(IZdpx9im!XnMH+ScjkB zC*M^K<9xH0a{SFW!`#3=n*RUo-~0WBu?q8VP7lE@jVD?Uus62z$v5%W*QBdI)?=FQ zPj;|HmEdGg;L8_l*-O@L?A7|&IKR>-i=xTSe$H7B$q)I^%MT;r+2Z)BOfhKUk7qQu z$;aaVC+rK_Lwgj>X`cCDTI)vnUiI$9mx~=A?j?`rxw%88N6*o+p2I%zla6|>E6{VO z*-2~@E9TjQL(OKc^#^}Pz1$w|w*jl^H+ldkslG!WFujcR_|dB)-fB{P`^+m9 zy`7nzbuagQt>@*w-#CBj?1ZuQ&`|uNz8xk0G;V8L(OSv7*sr@WF*|(*G|y4bi>1;% z=XKa~xoygGKbZT=_}jmSnag^dzBxj1`nAN**t3mbkJHOhMJgv)U!XO&%>C!H#g8+- zbdBZ3I)eU8JlK21N3QYjGbB>9WfyVMfn7=V!Pp1?Lw&M?=j*r^pB{_6BJ{o&y@?a{ zXgmuDzQA;5t`S|FG8Zd~opqFjpZ86Z|0tJmoZr}U3Hd?(t5<#5M=X=~w0>257lPLu zs6O*I(Qq&BKTn+ahU(dKIdBi5>d-R6>L1^VSW@O^TAImiVf5FP(`9RX@BO1%p zF1AgR)UTs{hx$u0t@ZaLe2`Kd^`jc~gT?+l49>7-*8H1?ygk43^;g`{4)*?*#*|{{ zSDVEnh{0icMtz?de1> znAoi6M-HjI^-KhDkp2bG+E(M+rZLjmRm<}d9qKnp_3zQ6u&v42rWlb=rH5?H#b+yk z=s%(u+V^OUNBdwCk52i|>EuG&L4DuP4`+Cuj2Pv)JnUAV6O=xJ(no$(Tie*FLnrhx zJZ~odmnVI_z3fRdr8hCfE9UCb~3cn9(%$q4F$U3!ScX$dh#CzV+zC z?w$aSqAK%C9c#K6KCk6mhI-O@ocQ7EgI4E{S)J{8MXXEjAT8a4^fA_)IbDPL2W@T= zk68c4UAqVVeapts&1uE8hmZYsr%$1?jq#9wzwLBB_MqSPLCj0n`QpQTfPY^%wUWg% zyR09jr=WBc)c!r}U%QX*IN84m{9En(J0s-Z9;@qZ1G>t;iV68QtgHOH`S0*=k@)SX z?Z>~bOJB3&W0_!IFTI1bbPv-1oA~9uf(QEIeYwSK1-^&O1b`0>n1iqTPHP(1_ z#9K|OkNM**ja^#Ti}xPqXXb*>c>I@smDV=Rd8t0eSi7!CBGW#H10V6&qjFb&)?j^) z`bA}-`n+3V>kqu|L|x6ByF&FBOK)W984UQ^bLt3m5&U(Lcrg}a&tuP6nR>RYR(>k~ zQz#!Xy*Yu8JoqdN^vjwH9}m?Lk6(uJ0S}YVI@Y}IG5@nC7#)80?C@_-9J+~fy2TS% zp+N_DeI;~pe8AlKdJAdB@}gE?3Gj9x@yC*!{!6>)eE^lO0BU_+3e@{ewTAt?@t=E} z6H3>F(t2kuph<+%RiSh|l%9Z|)hIZVD>06Hyp^0AjrE}+@1fJnb{_Sg!P8!eXZQPy z(JAM*8@sd)pg$aw*trOsj{@fcS90wl-NBXM z+QX$W&^}|xKHMYb?0X^X3HBb*+)f_e4N$4iX|7QG7h!{9R{5(HH}Ts39O6Uwl>PFJ zy}PMz_x7TLul5=L>Ub(Xx8bB+@ck9fwTZW$4HNH2MFU^)d5*N;_kbqe3y&JD4=wJm zDkJ`dSN!OHgk=_a1b9v~3*kA0?vwk+F{-n14RB>_d1@r^riv zjC(h!zAMoIKifTlbQy>lcwCx=%RwK}Xe|_Ty6a4P1!>7+jXN5h4r;FRx)_7i4s|xJ zbOw+vfi92wmx*r&dscM)wJVd4-u?}J4t}DU@5-Zb+9tsm@AAT5PdXnO-T~SM)s7Y0rP9!?9UBV@HhappR%yvij2}6epH9 zH2)UjmvsC%i?Gjch{s;=>Km3GIon-b$zSE@8J{e@$`mJxbsJYTzW#ZRuE52vVsMPg zzz2HBcEw+k_%Jo-&Um(y@v{8+tr`0sN3DNGt#i$io{hc4Z(3(Vxha3|X#JK<^(9z$ zehHn~(;xc0;w4thn9AJt{No2k58Kce8TQZt6W_vo-^L!6cVW$KeGCb&n;q*jU#4CV zKhotxPAB={W8hS#Hu$+qt9(Cc#gXnGemblE?XJGouXnjR^3h1y?#2w(T`eNkYw65;!V#TeCap5qZUW|1Y?Wt@AmYj=W!oG z{@1%mS_f6)Bl)I>`ZL+<9y2fZ3BQ|tT{Qj~{IG!6T~3U?X$<>d`7~4}d&T4PvJ0p@ z<7!_`S7-lRXU}~OSI*v1IMH0?aCbVK-lYm~?{TbtbscB|-i`1kkpoZA@Wn-pL;B@w{{6xw>H=Xh1%+CHXsiOXzX%F<8u_H2P zeC|7a=INZwzq%NV?dZ%*u(IB(v+pAO_yXhiPq0%&`=)Mq2M&sr<;duTQ@g zf7$l=Bj7ZCssFEFEUq-Xi-M2r{uDh;g87^GGTPiT*tEq9C(LQukF(_Q=iprAKC3kZ zW18YH$E1jV&Q^K1ZL=#sJF7g#evkF|p|TymJe}Rj?pTWRC~PWEu;1qYRfwiKGdwr- zmhc9?70_$E9>5brqE}s>!Lq)T58GT?_fK0%M?yO7VPGxe#%q*?+g$Y18bp0l`X5*O zV6*tCA9is*cPqLpuerFKw4U!7=!Xfd*EjYqqg?uFz0trzaP6o4d)JDWg`6AGCYE1q zS0w!vWT;>0{7fb~=-6t8)EQ(WB!*l!O>!=q^uIpdSJ!!?~BApY*A3uI7D zd;CD;_I3THrZY2xd(1cLd_p>)v&J>W%n{<~DDs1|0p9oOzsRmJ7Fjxz(AteUJPWPo zu*ztw!uYxa74gnYoQp9gQ^hrzt31ZJHWzbvk=nQ@?)Rl@d2U+w>KS5-WJekD1SPXe zzQpef_xbTw+{4^sI{P0u6TN$pTc_9%-v@X{iI}Qm{vx*2p4B~_nM5zo&2Z`Ynb}-( zxaM-rsO!x1;y=k%e2ab|@0#)K{2@IfU)Zzm0DHtk_Pz`_e~r4aw+A1|FM0-e+gAQ> zDJH-q*DfZx9bDVF67(G1E7Y@IdM;OO!MJSw8J$Nz>fn6U$(CH5r)zBeDYhyvyXQN* z%Vam_ENbUm%7nA++r{|ws}pbSBED58&~J;=Z!)$N@xGbXb9zRrunu1m*OBWU>EDpx z|0Q9qw%*o#$UZ+5i9bd>JVsnRcEEIXW`3ysX($#XL$UBd+NRt*V&BJ%#))6XmfA#w zF+}$r9y#y|eu+}g>rqVb>@2Y%`J=I4_cL@~X%2R1Y}oxI&!1)aj^`uv?%N^tpDzFx zp`(1KHM;d9efTPD)brcwb2Zo^-9)cGp?kTD@C*IG_LEWgL3a2)Qe4kUe*pQ?S8M3) zj1kXrz3~+9csW@|oGd+4A3=u3jVfeHhQW{OAL93Q5%1B?9~#>>v*|rm-6_=FpgAJTm&KvFi>Rx8qS`Ag z_bmBtbceNR2K`j$LT|99s(`-g6!gQP*K=FaQTmBqZLt05i9?4uXs9M`0v*F~5tSUZ zN3CD4|L}>omdIA~Q9HM&y?0VSehQg8i1+fCucPGM#Cm?wyU_kq7VWp7o%}AepUk3V zKXb^u3+=`%+Bfmhs~kj}%17Ua*2Woek;D7FfuANFJ8@{wyVTkJE_Hb3_t0kQXspX_ zyDwUu-q{uj+A&Fc)KTx*PYt$5xZP8#%i7}0%onjSt+p+n9?tvHw2Ma^E8Z%pf85E{ zn5jOl_sAnjzu(Cx+5PUnsIRy;UH&{O+kZ-#{1LhJp?=M6GgwnH2H5#j{eov~^h|I@ z&q-+*o(Y}iWcArz9=@yK(ldi0V&Byi^i3jTqtu@pxnp>*1ei#_LuD9zT%`LB^pXL_H$c?A^&eXaivH5^vB|q`V zfuG1v9M08!f_LJ8;W>8;^5nPhc<{|YPOU#a*Ra-8yC|M+LGMLe#7Lj))H|L!_X+mS zzXzvsz4Iy>)suhJmKsOYS5zjM^3OM%ER`uXH736Zy>u6S7n}FlT#6sn3HOtqQdhB? zW8aOYeK?!UrM>Lh!|{K>@lv1B*;}qFzb90FoQGVFa8+}dsq+-Y$+N`AvmIPX-Z>-| zwsmdI)Unnp=-AlXUCWv<$=W0CpU>zS#*Fp~e&|2cZDAO8Fbm-D| zJvI!~A%Bg_i(Yu0rR&`)^-0lr3B?8PW3dO=fDHye+51VfZ4w(6bKUD;g0dsb$#y+e z>#wIG*su2SlKlTude$>EXRd>vWZ3%vq}6729fj|zkpGppPQ0aefwg8bb%Xu*T67f8 zpD_m)@r<+1u=UOzebBDm@TdL1lcI6?t7CsIHXNyWxozlLXonLpGg`Ha}WdVu;i?&ear0(!043hEfsp!?$?_$O-nSu2m$9HF+*bA0Lt zdY)G?p=Wt{-Z)b!i2d5f=zW+H?3BMg%`-%MXb&6P$P!=9q~Eb#`nJ=(O7j8t&ux1+ z-69>V?PO~YvF-S3Oqc(qgZ$4rv0u+o<)fRPrP8@my!T5P?So<+q-#6h{G6U=3bjcO zJf)X-&LpkzI*_liBpAaUL0_%kk1&43is^&Ez1)aD)%xSJ(4K0Ib_e%=HdANM=2NdH zK1DsrwDE=>!P>5ddA6Fmi>cd1-5?&qyowxbx%hT*YjS zeNMPYJQc(8MU~3otFot%qp@JN;-39%LCwQ<%=ixDMTPd;(3QoXzm;I&5z_`r^9{JiI`M6 z&_VB#>=&Q7KekBE{~)in3uulr3B%0-tkpauJ=6yFEV_<%ryUDwAL>_o=si-| zudyT{{z=~l4`ZvT_1BU*tI!y$J@FJbhRPPzdzCuAEo%mBk#2g=Rkn!cI%s4|Ft2It z^(D!Q4~~=D$jg?1W($3KHdl8jrXJ+o3u{lUZ%=JaXa6eJU9v}WBmB}mteYg?+6K?h za20es)Ia<3()5FzUv@wv8})xR*>f0ZbK(yi*w@wBe;qbQir$-^nV8+rm^DrRua)9} zXHM-i&uVu=`|9lI4*a0!qa;^zug)KJZZFvzk*RvOhT5}`GWp;^-roq$Nvuv&{Qoyf zYm1!N#}6brX7|rX&hF2{rkpyzzw!TazNu$pOwxY_yZcRSCWhILjDGOt&i)!~v-a?R z-{}9Gvg;V+k3pvN(c0%t>d=quv)PK-W#EEXn-5OHHtW|QuAy^M@V=cUm zHSxAu{x4nDz^UZcOi#!9eyxoa5B4k$eK&OZYvZx(tyC^MG=FN1TtQi27ct$p!R3Wl zem!~XQ|c6wFRUXDLNqG7pZw%gtcSmk{stduEnNPO%)i_K-^R6_Yd2T2Q(xxM^N*(J z6YSfghPl-E&s4<0m-etG4gDYP?(jwq?^O zThpSif5qEdSn)18g+WPLkd%4_kzPK7pWTJC7!lT>m4`%==A4^}m<1z*2+usnnfmC)C7FmYp{$@-{E0>G7G<25%GxwWfSA}(_|r0 z1Nw%Env!vGXq0jKdRg0YeJGCaQQHsc#U~Dwoq}H=^S`5+1h2qPVP;{uYg$&XNhVv{ za7f($c3Hg6`U#J@@3X}xwzj-OgFr{u?(e`OW6;s)!CbD%!2WT(Zu83M+hg(imWDVV z61y|LtiGj%c39dNU)tKfGOmyF@n=6g1|-nx6$i`fS2Z;g(fZQcg(~-(!8Ek2Hf#J4 z3P?->ygpf0zlv{6tY{M;&Q=ow#B;0PA822(u-}GjZyor`+ezPyb6-L8zkw#5rRVb2 zHGFc+%BK&175aolOmm4U^*_ z80@bxWs-xs81lkkesY6{($hYUrG z<)_dc_@>_-d@z&vzEk?NH4+0ZsF6FRg)z064`ntb@4Rrzofo#Y5d6&yYK;s&OO~u4 zk_CgI4nO&y2K2x8CmHtZe|8)j=ok3MeX7uw4}7eUa{1WCxzc=`Qe6(c2h;8of-18< z1`hBdJ-|zK0$!wpX=U)+gYacOxo1twKo7D0Q(53krNh{ugZOQAkK#J0WBu8boMMOJ zWwg(frseo7ly7e3Gph6%`EgB4lcibNnv{XIY_O&+%__6C8(Lf1+gjJOtDTm%F^P%^ zY1?KRM=h_A%yvG%=$Fx=Q|L~7BX#vkJMf@eLt85fh6=6BEJ|DU4$6U;vY&iZT=5A= z`&TuNbEUDY$v(vSDhq?fzu>*K~El;xok7{yv ze;Ti^%++(4@C351wBH3U1?v0jrvvqULC#)GlxsAXzB9-zcAHn(PA;mN4eVW5&hh;r ze?I7@kRlV~%Hdj^ya?u3qkkDLsSpSN@r2VKM^9^3c3};zVmXg*>v@ zDjj(@s8wfce*wNi{_p*3N9W)#f%5%Oa_FO$kKbySzP6<$d z)xeo9U4B3Je{O|8@Ywr&ynfZEYL*Pf+L$`r!8EoVk(T2HXd%wIjQae~o;} zW%M`Tu9?I*@CfiYaBmI$po2aEKKK)Txubv4(H{qjZr^+0gS^*j0&4mny1z9;~0pnNZKHUl>UQ$Wev4wN3dfDM$t2;7OEfsL3P zqp$KpedU^_W~MO~h0_z$s;4GqOiA!pJ!Qr8>gkR37cD&}UOjcj)blMiQJt6;uL|?H zVzOarqmP#xPn|mVqA6FHyrTRo3cSL|@MxKLnl~z^+#4Mk=S}u1Ac%1J6Oca)9JP7> z$H#AAl8M>^4F~HrKe<02f3z^bKU;+h3IZ(C7s-hEJ~N+RU$1ey(Z~|{_$vWEUeoYw zKN-TWpBUheU%+x&^Pv0l>mRx%z-t)Vq51YC{0|!geA!KOr=kEG==UE4hA;F8Ls8Us zh$Zs*-+pg^Kg#l8aej9FuWktN8j70Vq2Hp<2Ke1AgkT82e!#O)?|pdD`|}ZF?ke=` zcpPqsNHmu%tjUSy|E<(B(Vr5Qk?B{WNUoC6U%f)UdOrEQsQjCM4nGV7ra(UwUSxj> zWK)Q-CdVuI>)U{W=y~g?{=`VCe^7N0@a!`df96C$B)@*DEi8mVj+b{-l_I%sCp_xr zes`2WzL@7kbIW53njezn=0+20hY$+f91HH6)`ZDx#dT_mL^l^Az6o zlB^jh2K2gNZc67;Y;~t-NHw^hM?^oX5{fHDubE4s?sY%q=&uz0SgxV3eU0*2qGG5q zu{J)T?afy9{anN5Qu9r?by9D*H_w|k+^dbWvrbwBB8L`nc~kbpf5K<6DtfvBe;P_H zwn~k>op|x?7G@=tc8Q|<6Y!MYcZ-BE#Kh==9}>;yxJF6MB*gmj?)ezR<^Mv_x5y4@ zr@S1=!#0o@PofgE)L;l2wwbbvDVq^0dyTRiDZAd5E$|X%*g=X^bxDZqm@8X7ST-U$ z-k7_g!}Lhu-<%M0`gTZz%xJaWGt@a_6Nv&-!Eu%GrtG35H%FhuE|jg7>g9kcV$M_} zdlx@vsVZ4uob~&+Xzz*gz?k;$;oFNJA}J5suq+V5jJdRmrR+zPmIwTRJ?mc-?$sJ}O) zhiS-DaK1{DxW2giV$b%)V9;AY$GztUsvV8<^V4eBxc*3Y`k%T>)OFxf^%~ddA`35} zKW$MbjeK$j$xkZjx@zw2&tOaR?iVP^TX-qnx#t0rChu!dM(-76)Z|CM4=nfuKM{=! zxzhy-cXkCdx%p^Vo?mpI=to}UnfzjLGkO1UA?XsO3-Sz7 z@=KMDnaD#T8ZwtmB&G79kCM!fib3ve#~?4b>06|&=>_v1u);r%=>_u{d=Z}eIV2Vo zUd+>(Chv1_D7;h#n!FF=)WVrcM@>l{2=8TO)ToTLbX)Zob=#NUCi^?CAuY!HvD6yD zHI$)a-&2%EHq{Mn8%VE=C19|asc;U}hiMcU=GEr>-m5jkw}81545bV!6i4o({)nGp zx|fJCfR&T=x}T<0vRevS*haUs?b6bs}ThXHyu+hWUgVh92i$j#v z)Ha~keJQlk;AwGq1P-=6o|au2rWK^0mic)LAC2DpXtd&VMapMhfcPcQu}T;fGQ9mB zMI>#y+M5|FHXB40h+$z}&JVEdVCRCJWU=$S05N<$h`?%1bZ2T@xE`vr*fy}>8)IjJ zN@<;&Gn1Jh{siricOkEh+n!;EoMM@1#;(NN=mJlfP0$zHA02nl`#%9Fc*-XA8@~bP z7G5jT-6FL=-|wHl$`)Hr@m!&+RbS2tp)Jd(q>Y~_d#8zW7T%bD8>*q`%^ZIHHQz(;@#mRf z@qBm~D~g5qG0Lh+tG=i|;jj%dxuFGM&h(oo$SZKL*O53e)I`N9 zxklX_bw<-0ea3QCcAX(_piC_9 zg7-pIw5)wCJw{5H;%+HB>lD>W1@dlt#Mj{M)Q>%pGWNHM@2K@H|XMZ%bi{o zrDfdqApciT=CltY!8_(@p7G0%seI&{s&Y(9m{D=~c{!fytM{-^qjnjiT)AbGvX9IrEo)Gc)I11kRQ#>RO3Z0CkY&l1H4>M9=Kgu&9Hf%yl@}cGfMc`fxtNu znD6zGt*GFqo6DT}8W?R&&f;dN@d`ZY8rjr5<|yTHZ$V^JL)@F6Q$&ksg%AguA5{#E zT_KBCDX&JPe3AX=#L5r?RDh{`Gua=_U$NvtQaEsJ8}N)WQq)i6~z z$mh>UWv`l1-w()Vq})gwTF!gb&lHNS+&JEYKPCN9VXeO-RDGk zjt#xfi}ksa_9(c&pyEj{EBP-<(okIzf1PNOXm$_|UiVr8L=APFJofy6$F7r7zaTrA z+fD4ERq1caS~+u-t-#zV+r{z*@sDh(oody!xetJxYHhkvHl>u+c}1`X z^J8b6{NF15-t+$| zaBFogUcG{=I>t{k*O?j?szq2qF0yH1^+e#OxyI}PqmFbBzw;~TNOzicQ(=E$jv!ES?*=(8<YWA-K`%>u}+xY23%qR1Lg_vJ_?iO4&|ZHb1gy&OnR_ zy&JTG?`4Z-DHPOu!y$g@5H`lBQF$1|PpNTsEy^mCa%irg)*{OI|MtwNP+6TTJ2zCe zk}_#}d8jPL(4x8vLS+fcj#IW`ux#R7%7PF^AyajqBC;2b#`__3ehBv}TFRD!P?;Z# zeWE#ck{u$`Hbj%HtBq%qlWb(96&V^^G>KRBC_469#+8Ku%PlS$<@ImG*t)SK>5Z~75Y=8vd%NM<9A>vx}KReDKT+qrDE0LNW`Dy!s- zoK1U|_+6_-a&tEIESY*j#ER?!DY7;DZ^s1g!-_?CcbYe4mFQJt;1Q0CkXUel{JWL|XBjwRM0dcedjkW4wr zptFx5`bvsEZ)+`JJ_&dGiRDvxjKFH%m~PgMtrh9rX$tOto=&zZ(57 zWY1GiNKw5`T7RS)@`~#y8gE;J#1%?ZlUPDxx~Qrbkh_mu^#@3NS;cE9KL2)dwt?5! zglphR8n{cmzq3-j)xbL0wtg$c8guqRq{}0ZfFJY-gJ96Waaf$(z?HSs(S$fLMJvC< z^0V6~`{U7%ElYpo+)SBV_-k8+3s=g8!2nsA0&T~^?Ib=5-LO)rGmnr8M#H^eq{q1q zqeieHclK*wG=tCfG5(xS8=M_S&reZhkwy5#Rg`I9Y<6X$OSrO*P}vO1G^lP4m93rX z^Ly5n5$`iLP`1nF=h=0}7V;Wo_lD|iqij2R{L;}Cz8x5~9gMX3%OLf{U6g$XYMEbn z+)Y~kdKmFbLqK~)~yEh zC0+V;$a2=H%?3G`%lc*3!=VzhhFKzNE@WbGoBHojQ8#jeJ6^YP4{XDGS;riWuyMWd&Uq``~r?z-6Su8ZyNy4c@cN3^?+o;enpyy!%J zOS-5=!mxy-P(edohAkqPFiHh}vich2}r81$Edqt*nKR+g--F0;GhisjW zpw4Fo>O3gQtU3jDcOAW;7pfuJT}Ll`K)edIyN+HYt)hk6T}Nj~ctN3d*U^h*V2O!n zcOAV%5+d4NM=$*&$-JnT4c&_YUa49-20yQR0l^T{qQ8`9z>QZsOcK0ON$}1p z?&a5>2>us|68%v4dHWj*-%@)YB063t^Fz+B$LPwGNQdaaF*@O!B;9?8=-Iy}Gjs*s z@HRa_(z}s5F&226#C+Izi%2PX^W~zku{eCO(lMpwKaB}q_ZljWpkhoFx612fkEr(P zJ&^3PB)e&Gk(@4)9!O5J{7+Aj{gblxK=gExjW1zy_$oDr6&mwnSdU^dxRYNyn~v0f zc786Hw8i*kM=864GLPz`y!l>&D*ExUI^t7}(=666i@CD%Y+0Cp1(?N9U+XZ1e+&3j zyE^X=@tI9o8`O8&GAr2^Q0Lg_HfF$Jtt;D>&ANO&m`>Qp)WWx+_m8^sqH4$CpOP~Z z@_83@h9a-~0@mbmXhIHc$7QG6^Nnfh4Qy9O+kP|i4d_R1|`+5f*H(1egJNGr_Q_HE;QtL4#^RTnOTX6TqTiWF2MmDLV^?1+ft+ z40xTf7W4-}k7BocAHP<%DJxQ#U)2Rt3kk3L56<0J$=x5v-G2ODl_L9nWw+W2%Kky| zt4~U7fNhsAmFAom*tHv!y#6_hn#blk!0Z9@43%E+F@tu!3PLgYGgrlrNt&>HKbTVl z&hYOlWNv)`bwsfe=ym^sa|DIVt+HV(t1jP$TT^6jP}cVITNP(_ldZ5D+1te9%(IBO zBQWYw?A^8zMrU0~Qcsec#T;qgP+}^HzmYg2T1}f;pU$_|=`Npa)E;R}Imk*9r>|PQ z!g%kOQaPJ;-9K_Nu~U`RYh?8~EVO*9*QChSDQm4>Bda%%9obAxwcK^oLt@Z!td+~xf%>aeWZv-K zd-JDN@Wa2v6jp;HM_{4fYvXrGh5H|XqiVDRz3wl;ZY*ltFEzY{<7~X#pHk+QaaM)< zrGj^}8GePTuT=G8RIgKMcRLFwS+P>pUy<6D!O9fbw+F0PDHfAhi;cH!*CZadkgcq| zz<2t4VdFdgjseHd04K-u33lt^yZE(tWY3rb=48kFv8p>-XT(6tw?SKJzoLplPEfoo zf*?l5>;4X$ZFJm^E;e3LN+^Q%k|u;n|!_%4#p>f?S444)@$YNhioNM-{$K|!E&u9eO^q@-? z3KRbkjdETPUrhxeOx3>&^PGGVDxKIX0gs7ZQ%o46r(SaYER3cOi!l>-iHW`CtXU&W z{#jwRshg+=gfQn^i=w$V+PkirJxU&grXRTG)L$!o6RU^dotLg@WC^PY5N~3e6prULLV^uK|{XLw_)wuKy^lv2Y zM?x!h2GM3>zc7!dz$ipQm~+1%JyNO@Dm5R7YvK4bLfk6)QF^boZ;CQKaJX^;i_G`q z_M=dq^z2XYV2^(*HF6OZbH*=(|Nr{oIrkWl7Sx+n-@k<$`Jy`4qP4RJMZm}6w*bAsqaQ>C5-9DRSwG57Ij+4AlnwCTh z$7(%V+Pa@y>3f*KOljM{GfI?pJO^dz>MArTt;gYcrByFrMCo-Is+CSa!(pYLr`E{Q zi({TSv-FcC9G*p%2q?XVneq)&y7DW=^qbO6DehXZ^#mL?rN_~1omYBdE5{>V>1P(R zxbjN>6I(kXCi3}NJZ{j*Kx>9nTuY!9{^P~iH1sjhg%B_0SdU~C7I<-?ibqP}Vw;JYq7rgtg=cxkMfZX@jP)eI6c0mI zVWp>*Vu!x~x}q92bL1#gMOO@GeVG?kwIQBl6%W0PlA+pf703P=Ix|%Jnc`vdD2|#k zRaNq|=SiHFPm1cQ5>fTy;d-twavQ9RN30^57kw|kBUe-4RojU2en7z}rjBa0tr^9u zMkK|k{MA9Kaw*_yjN(N;r8kJYxsiidpOYDxL8Ld)XFG+65Zj4^Y$t};`cyt!Kkc)f z7-Boo6O+^P#q}KTw}?Z389efD((H0y(Bn?f<%5DQ4+-+Ad_jJCwAKF#TYI$C|4Kh? z_xH1G+Kl{|q`u!5@nO~+wb>Vd+&SBy`W!x zumASz|9iIF?7i07YuJ13z1JSjIr-8ALXs~nAjw{0z<<&^t!~f4gY1CP^9FEXod+B} z11>!kmC{qCm7b~M&Q|XwkjO!|gBo?UAOZ_*0H{|w5_cjolZo#ju?dMjk061)l0N(8 zudmO|_#6Kjf43DJwGj|AEM+ktBCc(HSPrQv+d?e3mmE~dRfQ}gl8yjcG;x4seKQ}C z-b^I6B2l7OPNhWvJPg28a4xZ@csp0bmq-{rr9=Xe$t4Kly`8J#t>Td&ea%(2?0wet zg;Gt6fNK&HyCJ&ii~71y>dTjb9IO69sj~uP`$_$)Vk4QCMo{_7kS~{(xJcOIYC-8{ zuznw6kBNrZiPyRp?*W3X1GN$2L2HDx3J0Bic0D!sbk3+?RUl%ttjajL_&njf4}~X+ z!p~}j=ZV6rjKcFo;kzOVt73a23ak995rwaaDEuZ^C-hRsv8Y5xVO}i%S_=2(I1)gq z6{6`65HyC~0O%y7hCXBqXX4)%NHihQ$B!;W@8P8oPp7ZXyFkQ$#@}sKA%V4rXMkHC zxZMn1eaJ$25_u?3B9j$lOD9uo1N@poI*RrvLE zE~;8Be>-Y#z~4b2D%}HiY~ZuNjMC9rlzUHhJOx)-l&j3cH|ua;On6$w&ruUmT5U4a zaXfh$z)k3gcGo$GqC)2bG#+w77a?&w6N`{|6p5-;Nbr!q8Grkh`Y~tE1+(vo9*$3x z<^i!5h^IB8zxM9Z3Lx$R;*Ho64M4DZKM;iIRyr22$3W~y0OEGJ(y2ha2ty*WqCL~f6?_&2aw5=w;5|H_8WK;i=?N|8v(MvK=Xfm_w}yp3X& z@(al{{q7j{rJI3Zi|^5hNQ-X=f-U~D*b=*eV3q$$5UR@e0mdr-ESC5=AlTwr*w>1# z@?*fT#p?ufT8p0mdM2vyTwQP(jPMOnk}naMlAHz@C36=us2ibOBW$QuQ(xuQ)EC_yYjH-6Z$Sd z<#3eHb4ZLsqR%5p#DB)$ZB@K|#v$ye{Ozbcfxk;ZRKE|2zNJmz#epmtoYX*u5p1%@ z-C<4}$H>?!ZbwP?wB3I!RycM6L!=e>*)9skVM}HJX6*vTN*f_|03Pi}mb=IIGs`)= zfZ@}d$PJV!yXbzfO=zYe3Jd}bAW z35H&f24m2|!)WMEW7#lT_B?V!__Q#?Q#cnZda_*urre1_o2X5){@-W3H=1lo41Qqy zux2}&Y~M3%N0V)Gcd+HdvW#2YY=vJ1XKwPxao#M(Wn;;hW$aaBYJArI(AzMCNZS*y4Pt!Mz`c5HZk}G|G zpczjg{q+jg?e?E$tUU2M@}XJT8xYLHzh5-YZcG~27lwgHT! zcCRAaOUbqglw2vXTZ{x-8OUS0+a(;XmQh_&E5131I9LnI$oE>qcNzI^Bj4$uWSl}x z!B^ER=KpIYU*OITN zr>=vw?o0^E&cuAx}Q*uf4$IFJLV& zu8khXen~gDk$g$5+;*Afdn5T?Z}{FwzTYL^O`z0n>+n6zZ)ebNZy{&WD~(^!oNpoL z=M3jt$oY5Vyw%azKI=Q zJhX@!-$~A-$H5qe^dlT)!1+#cZZe$jBgAYK8YN+DcDnt-9?(SlKurvt_?_mWsP%|LJwvh*}IYk{HUn`4V?0)i`wov}rV z_X4B01ngmSSB&8?p>F3)X9uIdO;31$?ZvlwY{y@;7e_6$*8^;?9j3h=V0*n}+H03; zuSJ7oZ|)&7K)Bc-yK@gS_j^#5`bMZA^Ga~!$P}v)mg(-5vWzLEc_{P&tX?C9ROOWc z#O6NMO7;p-i<(#{yFf%u^0^@eECk7IY}B{xSxK)f}>5 z|6{a2n5TQfW3->I@)^SSbm+0xXbYJIU}pK)wr+ z8~6mrk%No{Z$fsEY+F6Wjce{&Z3P>~aU7M6NYy!(qN4Wz%Q)^)!OBs4>6?Jj6@DwQ zDIR}Fmt&YGOCPnP)uER@%fRPDl;P6GhN`S7tdZb8%NbmcG{Lp*lMrk5AIhofd77C6 z{098ByI$00K2I|rG-f_eGhd6?^;2b+_MgMQ2dSsCqqGTJxUqAS$j6gF^Psb6jtf1? zRobnh8K4>(g1YmNU_X06$d#+C0*pII2OL=OCQYXu#Ognu&GRbt?g9$oB=j!GRn7A% z_5Rf8{VMhD0e(YvfRdXuqER7gCwdn69edInWJyBBa;awd23ZaP6PdN&Aj?b0a+jNB z(P=D~(>b{gu}G*`KC4+CCCgQY{&>oKQsypKx0OOB*d9DC4IxaGU# zc))OcmmJ?A$9*o2XP?Hgjyk?aj-*pl$r8=+J#w^qX|vxWM>g(|!=N-%NuyLJw`owF z6Wu|45xc_&y1@-_90l<+o!1qZZ2?Sn*U%XZ&_J?+g2Ov8bFSS;Ki`@7v7{cXhbL(Zd?C z70n!YhE>OfdNvcTpPwaNSIJupzZEW~XjH-?A%zHhTEcPkxC_Ok$4Bi;u( zbp#7?%2sBQIGYw)BY2tI*GV+zZKt#~f=Bhi8e%xUIvAzqh;p=8>Ul(8O|-CN3iZX2 za>NukZQ2~-xdou`V&F*LR7gKh{F3uS_RXLX{3vS#ucQZSNyj+FB~%&1vwq)pGUa^h zpsnG&^Wl4nv#SFYW3A!mpu_uq%IVdG5>i09T2 z?g~`aL+lw}&l9;}a4RWJzh6M`9{fwV4nMuEIN#&=>nBv-H~0yX&g(>c^}j?u&UX~Q z@;Z?ZkVxhafKSSAU;OHe2=O+xk{1r?iwKti8IT*jafN6}D}~!+aYfX?O5q7}T=9!Y z>KnarC48JHAQ#xT3=v~PsL%ny1*VEyamZP z9~q?jGP8e(zd^ac9+V60LAk&l)EC%!O(NmrJ0Tz~xe=|Om6HH>4Nfn@7#qA9v9u@n z?g`ixJash`4bGel*1?i@;n%^WmryIgqTivjuMGuXtHzxIX!F~1aG;()8VmzNafl2Ifvl{+%xWLlO-4E}TSm^5H$fVhLn*$LQ(zZp zruX|(){v$}dP2%YOwT1vnw5DMj0^?JJokfB)+m_w}()#Cr_WDEnV~;ReHhP_YXM_jbO#JpXbso4x~BZ|9cfy|6sLh#Yd^ ztG(o1VUle_Hh&*WUd-z7cJ5i8zXxX9m$0t9otu~Uel6W(Zv}Dh&uPgFYQCG9EoX`9{N-p15HobP|Gv0)T}9yFhlWgBItGaI)ZwNyV&kC!LXSJUtJnDJt&~_BrgCYUczA<8# z7Fr^(Ni3ynU@tH~0rg0YN&KV66dVTTC@`U8x^S~1@pf*4>0)4^?=0;3f=1_+vt185 z)3=YsFbMVl7b&XX$U#TRb7;=ym;VI@w@kOGdL*2g*AhT9_AC9AvZL zJ;;~BeFn=#%3l#H9-{J>_JOt)ki@#o#$qJW;AnN#BK5$g;~9b)~>e+jl_bB2B%q_zf1rJx zJC?_r^1DF5s^Sd;7L8O@=%6loP#3KydS!(3VW6qZFLgnu&mPe%PoBo|n8u{S%4lI} z=cs{Xm|&)OF^)LH2L?o3NaA3|K?J)qp=yxRBPI#C>L()sqxW7VFlUr9md*g4HFc}P zOHKJYyPT?M*94Dh0vhb=-0l#p00HZY7Yw4*FWdkOM^`P&3hjaaOop&OYF-@IF%BDD zJ_MShb}u*=#(r<-PS>byS6d+qHARNCLZA$+28;$a35>V3$Q0F4um$2d7Fzv&4L9UF zm)nuCyH0_!oGdy+V;XHpmyB}X$y;)S?GcgPfu4nh259z%n-q^_Q{lAc{=IDO|2Y+bPOZIzjB!_!} z3vB@#w(`G;8nLtY4q({=r?ir|qg8MaFd4QEBf6M)eXhPq%U z0sAw=^2u*qvxR&f)HDu8R2a)qYAjXdJGs~5uiZ5!sEi#;V}Bkob{viU&=}hoW$buz z@D{$MMwB|a*S#+N#r~rPiY(jL4_!DVVY9rb}DlLl&O`+c7$pf zvU$xdc)!){tp7WZ&A*S0b_Ywvc{jx2y1Px6-MU-=dsd+iJ_YX)P!0Z#32ZWS;I=GO zQ`1>IS+#;(7ExX+o|VJmI`1d0rZ4BYdx%OKr!HXFU7mEM>OE9-Z$wq0dOf1*J>>sc zMAdC973bX&QFVKP01i=AK0@$+QZ)nQq8gUA)Q81&-cMZ3e$Q2r zw{yp}>PGV)C;`*=wfTqWVIO5mcIUOBcIdDGwf_=SV+(Y4T}v;3bB1;R#ZZ_xb}^)T z{8b!+Q~-{Fh*7Wv!#+$roW?ke?L`@O+Fnw|9kM+K%xw@fOfZw}AxaEgkOf}``k#TG zBxp4~daY~up` zx$A_tq8lIRFFw%CjyS0 zY&IOMy8Ae$uMsP^0(w%cd*ksCjI%RqzrBxiwL60ts2>=S{#>aa8FTDXNCSdcbA^HeJK$*&_j?f3!QW zf-!)J^UgrxDipZEL53Cq#1#Y`mw3_!=Eu?n75+QOi)TF~b^5Q!4wl2U@9Poh3}_dfok0ZNDge2*8Olh~9^_hxo;Q z(fLo*QT#v==Ji8f{6OW;W_~ZNKOjxL3VGG^2POYgH-BvkdVbxJkKC_!$9VzIQ>5R9;~}K?^J|5 z^4_7idX8yyYB}jhrl%wml>9M%tYOchUj~-Q9&8F6TA>6l*&M*&Uzzyh=Pp5$DOWp)@ za!jh8W#W9_2c@4Iy88H(v9IF%ISGchz(U_oSY?hpYs9w@$_7??xc!z)ldOg?Oo)^9 z1h=>xjYs0uQ)OVWjyiI2Bq*za2Wi0pRE%>=vTXJa{}$ZY_kFHI90tj7U-0MYUtBHg zfHRh(i)x5be}MSxN)CGsJdH~oK}xP(Rb>wQGyFSYu9r%1(Wz=gapq}d@H}F;=u}O} zZ6m9p5rtBlh~c7BVYoqUH9U^0P8Dmpj8Pb=Uxi-Eg2Si+7aF=f`A+J%e)R+}v{i*9 zO9^O-Awc=*mJL~~%n1a~iI6j=$`A(fHj-0DLmR}UT}J}mwGna2JV{7q7L?SiVJ~>5 zKYJ|zj4c%>o<3;p)Nv;x38h^M%2>mGN&jBup%ey1ind`Z^d7jLw)tLXI-3UTCj1`Xn%^gG6bkB=tkRBRce1 zKgU8rAMhT7LVSeWd~@d2;aGlMiD^`wfkwaEdo(zB)Vsa$hwtXbAHI#-qn|5Rujuxu zcXNBxySY8;-P|7aZf<-chM!>ZsjoN%2eCgRO_?s%{v8i$%n=0qAsrq%@tD#~1liOLC zN3-!C??p0MJ`j;`{&woXZ(}4(+6b@};0GcSCf`PC%a@O${(;{>Cb-sr)_Itl#(#S?)}PH2LvfwBjI&Y0VblR{~-zz6WaKzTbTe1ZR9x`OF=%f~0a zQ$~`=$0xp1Mm>d+&=S9yIL^xmQ9xD@0_+S@(S=#jcGnsV57}IQW&9At_hO>YUb0+M zJ;@xS$Ba4@e+#*8a+;P&7M~;AeG!ziv#vo&Tp-G62GqyeGF*7P-i`lI8uQfmDaz5tVa>Z zSQ+ggqup1-rY^ub0qZG`^7fRC2iS+$i4-eQG%pP#QZw;BdUZaBV0&RTP`iN{guixI z2s4+o=0dinw-Wjvr~X3Lhgn&TNp=FW2QmIB>`G*NJO@q()6jb010@)WLJJ0{Py>G^ zS$Ri6B5GuDe7EnYhT!9Xy(tPDH45B81@58`k36J(q|XU(g*2<1*tVO3dWX@R9|F#L?2$8BnQ%Rd(>OM{?hzd@p&IB) zF@gKxw0jv?KzmkU{^xAn17yk%LvF`kyK8=e*8TwX9SdQ-e~8h>KET2MR%X>}lsV|{ zX4c0Q`jhV=`vS6}{*%VVMeC<1-~@05)!^7|5x$XbKl=^9vVq9k2+3l}9&O1)C=hXB zyPl0fOI`xHNi4ylpLmx!`Ipj=w<+f&$PVJK-8B>4SiJdd8ZrV%Wysq!s~SP9c83nHO;S3#QHUU3it&eW#qdwGEf5} z>!)ZVXCgt5>ks8<#7b$dh>;tBUgS1%xwIJ?l_y}Z7{i=u!F(@GK1Hegkmq*%wY&Nz zYLidVOg{A>&>hT*$){-Yt;lA}7YR<$@?IGN2Y4 zdE$lvo3^ZFUTg{2H0EC9OT?IfO>6kBzcOjS6kE4oUunS6E!Y`ps`JE_`2Miv7!(j&(xxd} z?uQ;{@XRuxPiR|QPFc}NTQ0YofX1W?hs+IVJ1!SH&W4ckF&zA7iY8Yf-=i7SfeZv- zpoJ{DI-VY|DpzPYv(UJTYZH44p^Enm(91|Qg}#0}S#1WARX15!$q1OY6|hpUw<@@n z!8YNJ2#3c&Cf#M8X!mGDyEf789kSd9YHIgAVd-f1l7?&T^0}z7SFk%0Gghp>AVq7q zf*N`UU?h>=wSt|i53*_!Tfy;h1hQ&OTuCNZBHQEGG-VFo!>9-J9w!0g`NmLzxm+pF zccE&$+%zOuIl73I&o9E+>&Z3;sF9)@-^M7lx1PG)2ywknv4VwcC$dVJ4J`FCvOUUB zly&>COPP8~f-+AFOpbK&#sEei%AH80OO2}i^p2aS16(F5j7`-l+)Ncdf{^Ta3lRt3 zOqu-#LgqZsQf2`tO$BrSwhS@{2ux&Ft_4hsLclZ;!y`8mu(eE1M5^|921QDx1+J1I zVcI~nzYK6!VOJUfF7rIPzRD))R%Cl@M(NEE_s=43vR#V?XHW)pL{#2R5PTm5d3%wd z;Rq9c3gUQQA6Qk)y$*Y&DDoT##)##$L8Hh@QRIgMwcwQ^_%&pEybNj{An|-RBJ2c! zBJ2w!L|8HRMC|K?O<=mI+Jz`oBBS$lBKl)+3|9dCA~=StkvN8gRm?pd`z9$|58y%3 zZf~UUO;Y&mK{)Q52lRiU%)>5q!bc*EUT53hEsXf3Y|PW>{a)0D^sl?6e-#ZjO5Lsa zB47ChsHv?oaS~!uZra(~g%yz}g%x9W^<9naQWlL|%g^7%WiiC(lE%+T$*TPTiUfvK zBRP{m`B{X9Fbi<5o9ei$l~#Eb2;zMtt$huy@9X$6l3Wl7t)Dro_7_|g&L`315e(NU ze&>e>FygwS_7peC+DOjWSutWxiLWik`;$|@LBO9PXi3riz{7_@HIeJaTE5^qbxRA9 z3`7;9d&vkbX}H~myOF7{k{d%jMZ<-$pR=`9%NJ&+-b5A*juiUC7#2@cp}R@LsrO7Y zen-FBQK;P1`$^52>`Y4e9r^Y5gF1eKO>#~aG0d?yPW-uo=Lj3a&Z>PIjS`$d^EiGh zG;{s&mqB(vz{H)qaVvZBTuI|P>#jS+( z?9c3W{trRo-^(8oTXm%{A$b@bsdf_jVe*ZnWFPZ0~E@2Eni8VKAb>y zCsux6k@83%}}Nhi14U_rlEgm9HL;72s8f%k-94^d^_t`I65K z>%A_$U3SJTFSBE&H?(}~pU{V{1sUwC}qsE?zAPJ&y9ZBY5q_I-ZCD}BReG0M={@PtPX|ib~`zFZJ0vBT} zN7bhz6p4I})JmPk!h={i2L#ila1ecsG6u2mP87~418yJ+9|l|VJyWj3GWeZ^2|&CX zi)hl~{!|@8DcH*V7(a_pW+(pIUClsd#etnYHTxja z-I(r9U3Y`#DE`_LyYMp&buA<^ycehJ$qQy;&h2yL6=C0xQaFssP(LDg%W6pPmOtQXPPoy znBF`;@b>#=1WNx*l&qBW`ECL#jv86#qNDq)`?}#*b;&pk9PE-OVGBQLe#<1>KtXG1 z@7F!k>{7G$cxuOiQ5=){gX8c;jQp45H-TgO0{rvy2S99gv)vx_8pmOz%7o$*3=lC&@mwFR2ENFQ1k4sZ%8RtfVhM zjnro)eeQi~U#bOq*{AjeF`mLCGLXIGxPi~3P+)D`S@X%0d&zO*nS?*0Zmre$m)eP( z-b;=koh&z z-<~A&n%ht)19yy95uJf;N=amL6WCry?vz4BvVKYW`$%SA3}2+A`y5GvNZ$~lQIhVX zr0j1Kxzhn^a@+Hv>}x452Fxz18hEH0k*+AP=#|x|SnsqDjxwq=OLMU9^0jN*4}= zUZ|O$FmpaKy?)QqlD!St+`V9PE@bfTNFG;-5XK+5(~x@**xA7D60E>_9|nwek;^27I}?hZSmsf&Q2sB*z5m8t<_b)BuL zRmG5Z128uMbGgPO{#ol2nhDHzfgyL%QmtnC3`JM4FJ+67VxQC|U$D>GymSGwkFfgK ztn$_87m+JC1j<1`y$vb79%E&;uz&K+Sotpjx8KMy(yiPMfL{an4=yv-0!A|e5EoI4 zn`yb5fT0;B24fiIZU=@HKGI+!6}}so_kp=gFqmM$l0T}-_5th1T404KXE^5jacmS- zF|wUkcqeKk52zyiwYxq;)LZl&B(oZjco>OUOgx6fO-vj@;xQzOUqk}kqU4wO`z`>b zzeb|WLQ}sD7A5Z^mp=>^c7ZjU)dMJX#Mqd-6ENDw&nY_fLChXt=pF+!Mm0Dw2Z5pX z6HhDirk2p`l5iX_*7&uWdU-_lNnlvxTMZwnA4=f#!S1!o#itCg0@UWu1cr+*P4QGX z!Ybn@ar}I7)jvkF4(7`*sL7*=zgp#A6sI9ehe~bx(}{!`T2w)W=#>{YNvmH9CoId#}=&EV{m>+?% zi2mjup*?UO62w0!z45r+YH$ftCl;tj#y8apD6?Rb-e%nStsX`=h z#dviQxL5BwE;gcB_fjc z0>feKdBLb*>=0laWd2Q28>hj65fC)x3&X|;&OHhY$CxzKu&I(2P=>6FT(Av*(d6L* zb63-5U^qfvtT1?_iXJNp+(=1)b-iYb`^?@C~O#)frWG0Kt0U8&0DT zdx1C?h@T6>9XYU~4+6``;WvU+mGiPL;lu7_bgaP=Z|V{`f>k9x)FlR-u>^+$%4l?z z_yYFc4m*|-7C-qm-;~>Y@ts>&pYr#mMesWI-;a~}VsM|0r5i~32}*^tazlVU1K4hX zO~H9K6vZ(n{Sw20KJdyN3$p(J86RBI71ettV07@@E+iPn{!#HT1BedcWCZb%F_~Qh z`a_z&0z*26od`XpvKm0>Lr7-GUjjL!*s(%BDXO*K)HtZ?>)aLb0;^^xN8D0Q4ktk} z1ApzVV|ofHU4ZQQ=&ZT^Im(2)g|%veJizFR-*>^v087Mx{k&2E51!~s$R7zzZ(v}D zE0jd@S}9x%okRgycHn~vvi8iQ5^>(WSbNs;eJGxX*n4E1=D!{VtXjT9#Iv97t)Ma` z*7BO4=O=VOHsPEn+rv1tBx-k@oZ>7TC5dQy+{$UBLE<6@;$CHpw zq~y|!daITnwecLL2RZ6kwQ4J2L56}WTBlr&yA{ODrLo4w% z{K+@q1?|6OhksCiI^JD*3Wy!T>5^rEqUQVIZ~grSPaA zVGxD;Q}{{0guyg0VEOpD&4eM8;N#~u6NautGQme?a`Dgq@rU4*F7IT?&Up#o|N1*w z^!2{Sz)-!DCFxt17mBLuedMj)$&z#@!5%Avj+cgH=7U6`U6T8}f^2Z%G30}Mn$-%* z$8Lga_oF~iK6Vq7kKF{zehgcK^0AwseC#IpAWC%$4o<_iLh?bv~_f|udX z2`i{Rb`w+|y9wThDeBL5P=D+u%e-%7JmREm{k{=#m~8#N5oUbZ`h6qJ__Ou-UYUL4BoVFGOSFeIsO+m95`5LNCe5*6$mc1WX=U^bL?F_*i|X-%6Yhngrj4_zlQ+ zXi|e)k(Pd!n)VHFQ~fSAo%hXsYOG*V#)`z*NTE23_*gtOV+oU&@R%!;uQExHSDAE6 zM1Kf{g1JM`ZYh6)Lk9EM7jYRCh+saufNkXX4WG*f0}AmTwj~rRBGR z%7<5JS!unWMKZxh#y!8y)n{KhkFrzZ5usqk+t-FKS$Q3EaG+dn?*m!BoUm62S)QEE zR!Z9H*~;=gRr&t9d{0;TJSlJW>JGv76GF#%A`kUvcl`uw!`=}1gcO*67AomQ^4n*# zdH)ylzhr*D&Fs*ykhshGbU@*$PDlHoHLf7Rbg5nX0_Kfc*zxvjt|DvRboR;Hn5P zwkf8*&P{9L!PVEfk$)%oI$k=cIYW0Jp4?qS8+;vm52A1p3J*fzN3|$eRy-E4aez^^ z#6Rn*vU-i8^R$Sww6hdC4?d}h^&_3KMV#_GW3bj1r&4r$Q$v9~+%(r_cl2~lS3c7! zKGO^6(#>8h>A^)g-<9Hg4M3F5LuAtc&t8#;I{_Z7JgyX@u;!VIci;8$oZYmVD z8(Gu-zBG;3hzbuuMK(G=JqQ$A)+&4%KsNWo0yNF78)zj;9R~qTe@+o-^V!@V0&^2E zZwf{>G7GDr1s^;6BmxufAfvHB(L0i1nRce)>44EYSg##aO8f&?kO3>)4F30mKi^+M zd(dlmMVV#kSv!EHOI+gOw;M3J1Sz$Tp}KlK!FJjxRkZ^W(XeQzM^KLKv{BmW;Ze1jAxg(}XEqOkY|DSi!$?{O7pC)UNwSiC`slY()n-Suq* zx-8xx#k)|vz~T@$!X_rp`&^u@+kd3A|Kp(OBbS6m2`9carSLG=?MDsGK@nX;s*|1o z;!Pk{2?Co`y21-T1tPg8PWuHR{irz53f6#W8Y_c?=OZAH0L5#SUq}Pq;A{{A>0#0T z#Q*{e=>GcAq@vV4ztf(>grl5V1h-wCoCfQwIXi*o5DBrn8)FmQnDDs7?w5a!D zMD^PY#5CnusxOo`je&@}$axEJgG9m%tiD-Ucd@dr1VdF>U97BsBL7{QeS_^zeWC=$bV*p|543<6Zt<7;eQkP|BC!q zX#Ow6^4|!=TT%QkApdWY|E384k!h-azDfS}IHUhY@*jk3;SP|peyTtiRX=-x_{7b> z*KOm#f11gv5F!h%uj4Ucw&t5#?+JDqyoQYBH4_A5qTjjYiJL zl=D2YYH~Qm;s3YH%H;3~vvK1w8%Rw3shSN&s;S~Xi7W)Na4)1##p$>~hAMET`NG4% zaB|=sH&%{>+L6iOsK#z_VTn;KBWTA8LCR3W|i{g8l^ii z?@k53s-IBMGh`8HLRA;FtAO!<(oF@7V*sRiuM1Fz!!o)TP6vvyoJ6oUHVJ%E{5k+sD4*0GqxiqBoChL8DD zKw?GJh;IVHhFz~X=@|b*KpzJ59z`xqt7d#3q_B-1aY;@C%tVz+CiJmte};N`6R4fY z*j=w=W2Ao@pngplFpeWJmWh){%w@ugx2&~Dlr_yq%c00L6zIdmpz-^n@R6lN;Y5vpRq(EWuy7_YGr;+jE~#A9;k-!W zyFn)o3kvUWUaRo~qVQZUOAQxy0l!@8M>YbS6*-=_MK7O)ViK=+x58hr8<*4gIPdg$ zJdDn_Xsj~?aaMQ_3C>+C1Z5xye@wtc1^5&z4`I2-l<-<%ISRUXhm<%1f}!f|2^>PW zL!q|JI6}#`uQfCd2N!YmM05Yag(gVT@C|6`B`m~MX$*}u^j+xWeHyc>j428|5IL*i zAz%pS;GuSqMe>704m*tKBViZ^k3?>=B_2TKB+C9Y_lAYs8peZ@_zaFFvO}HN7bWG# z8rIHzv=S~95~rabDkdC9t)YB3N_sC^z%C*?go(_lA8tun!}tjT?=E%?(byWs6DIF& z&LheM7O;l$^*iZ#OxF^_&BjDYIs7OyQJ5ykRsCUn3@D?F!-3kI92UmGTV@Ft{SIrj zOFxvKILP8-i8AU6(DidC;ECL6wTAK0po}n=*^22ixNkl8PWipMjRH_Q1zVy zGUw2*e0Lb%+2Z{^M`^{0XgN}{hTTB#E1DLKVisN%g5JZD=p@A)CtYR9z#7IQ%D8@a zM581t)+hMx0V;`Hto^XUXKg`VA5lJ!$%RLhypvj%j7QB8O#XZgVsw2(c`}6bt3y## zUwroY;@TE;ASW-?FjtWOg69-&g#uprUPt7;9P&PoIA6T)Zt_=8DR|XuHz+aQ_b7f7 zymGO+_DQ7uaxBV+6@2wC3dJkjeuG`uR=lldYWLr z13<3qxL(gd<+)K_a6y2@J_m)-UT{e}+JKI9S z@@{$VdNjCW^ccM8Uj;YRPjGkcDz?u|tI8wHrm7faA9bi{<@(#XPqt z#@f!`w^*NBlmtNW7AU@r(t;|pN{Rsc1h6Lr##Lysijzw!fXP5e`l4WDRZ}zrutLB{ zv&>J%-j98V`AXh|^}~Tk;0gqyYsr7P&@Bb}1kjfPohxXG!;3xzj32TkRSQ6ju#1UK(Z*@+JE~yaC48Af^2^x)w_h1Hm^O zIwEeN&#VyP>m;9iK2#DXS}*y& z$oH0`fDJY~F3ticRzEof=%yMFzy_(FExLNTN%fpd zbERu^m+EOjzGM%G*#hf@x6=Yehc#<0%F5ft2AC`ojsQ0k!vTejk+o7PZ`b&;Ug0$p-) zkAn}Or>h>Bf?R78ePmD435K4qUAA|gJDh!`p&`b~m} zjatN~u_AT=@swLcKRHmz7ZJN6BKXY&ipUocW5H5c(Mv?krHDgX#3dkgk1Rzm194PD zI1XXu$)0|#h&c{|YN@Q3wU}BFvmqj;PQ*MxG1d}QSx?7^Da`_c-4Wd_M z(Wij(y|2c|l9!jL*7c^kT9>2Fhd^*3DN+c0B592?!;ruSRwOt}5#Th0W1I{%MCWKU z?>cj+QRsRKCVB?Y9Z+P0pmFbI57^^TrM>tg+v6qepy24URVY-c4!|Bjsa+a|Y{^>u zaCYJ`r{TU8Fn(J6Wf$Ecz+M6D3xPr6ZZT-36v9BrSI&c^?@Rbe#ok2;>yQfcK${!J zKIl$il@6?^3^3z3Na_R9&1|a%ZBAshiuCRsd{{T|uQ@7J?N~YpCo~^$NVx{%(Iu1Rh^~V5LbO>! zI)2%=ZD{B2+a)W2VB>}q0=IP7xRD8L1JJDBdO@qU=>jZ-db>nmd|5U9MFo=x6gjDY zqJ+A!Ru}4`sN|BD0AsDLcVI;)0W-A<8moLJUH&M|_G5C|Dc$k&3{|T~S*sVqL{+Q* z##&vEY*iw*ue&-Bt1rv$XWGcPZn2W*IvChHWzN z0`QXe$NZMdT<|)urs^0KI?iPoo^U|^73O~z$Yg#u@)MYUFHiD252${55UOJYvh0)V z(sj!;f_Kq#fSZ;<(kiLIFI(nrkVRSsRZ=n*h;gW99#KZxgoqVDuuYy5gz7^(0GkKm zKMM>GZfrf^a(ZbMerG`@{*E!yMjc>9E!jqys5j&JF9XIlDs{m^%dsk9lM9R=abQme zKN+p1M~Mu4#6ft2yksnXj-t#`DZ^)0jD)GcP{J)5qxjIYW?()?nTG{~&pXhwIH0J| zX%Wypa}f#)T6yC}z-Yp&F4$(kIC{LNVKB9*3or`RN~oO(wqe~SGz0FK%H9SWQT8?} zRldUH<1BSu;W_%uZtyzJ#_hU3OZnw<^vg@pz{)S5r(fQHtn$mBD8D>z{PL&DFONN` z{ZjIKSX%t@FlGFSS^DMA=$CoZbdMjoLi^RLzl3Vi?GTwgT0RjNO%x4a0apc{B{`|3f5}A<^eUOnXPbOHele zGJueQ#1|cp@KtAOCA$Hj^}iS4uGPj%Zc638h(5-!2QOl^e*wH2$UWUu(=Iv&@OL4v zWY9`n$UKYAr13f^2QL+Jw`=@EQFy2PT8)2J z<5e?I@@9?stqbE0*>?heJ0xT8fgzSF&Z_4$@*L1IjdWGRXmP4%U~uWnfNQ5xfp|Li zMR`sseI&!G+RlorW~n&uhY8p~=QhwRLlCs8sakC_e3D?g<%yO)@2J>Le_w;Q@a=D^*ve@&i zAv{n@FX8Tqf^t$79@Y?bPQ*MPy!OGm6VnCCs|WmJ)517 zA!{%{DUul?fQwI8g(!u27?_zybXNo|sR#>I#Uec3M+t+~sSlG}uPHT#!^u?Z3|41e zM02fm8d{xsQEje~oI0=u^DHW}hy}T{Q5bG>>RRVnRAwR3T$;q9hp6wCb2;JSIYb>? zvd3uc)Ugk(V+gER57l2jAn!W~b&Qwn4#2RVx($Dl8TZHgSRF(4`{YT?L0YS+PO@0L zjCiH?tigQgYeqlv_hYPewJe=KiLIX`2=)?HB;NNPWHjh+6EL_-k~SF37vW}{MOK_L z&d5qNtvVTFMKcU>DkVv|4Bus%Q9(X;NBG=MMPgJEtZT$=vH6qCShjkV2^>buDASV7}Eq``K|Qz>q?<0*@k8%??p-_2=BDO5*ka zypb=L%{ZIda3WCk5o3pFKZFN(=|vrp;v$$?sK*g*2oLbmi#aH}G$WNYL>=J$AQ~lE z3I>BGfJ!D8%TBk8Q!|sjsky1?c1Cm2iqCsEYrta2rx2n_DanTJGAKg$1 zrlI|+Srd&1BsmSAtQ!6dZThVan~ul8PMzp{bdJdIOo19Fnl@YIKGt=+L_GTbc#XArq=uZmKJ&2OZ`(0t<`y^MeK zb`e0msD>Vw8Qaux>?{gc;8s?F3f&;meYsPxO`T4T{vO@Qoz5R`TKjZ2VDFAIy*mj` zqnnVuJGQeMyHmt&oIIsQ`&`gxJ0nFJUbvH*hi$2J$HOv|heb8}xJ=c9T`i9GcG^N= z@$!7r1UMbkSgFXUmO^J11LDT1F0D)HY)|c>I-Bbn3gYM$d1ffcH$KtJRRRs$+YAvQ zmp@1KVdHRm6fDsCV2tGu6Vrl+(b^nd%*2FjVRWx8QtVg`V~Xl-kuFu@(j4}dx+})?9gHeY zZK*!iHv)3aV*Mc7Dvw|!82taJt7(sdhaq&1IFXFrX12oUE}^Nr9M z*94aC;NWA%$uo_UXE{y{-=R|@Dv{QZno-kMcimpl33pg@Ye|Nl!={srYhsFtLlhfK zOlDq&|2U0~*wbl7i8^CiIb>W5j-y8A0y6>^s*&40@i-1!;_~>&G($%+6V2&UFTPmr zo_hN^#&Uis*LuQS4pSB6Uy~_;eWknFl&kC64zrL_I_!9Iwdo@@L}KPKGfkc2;<|V} zEzHAs(m&cYqx$^-r)sI^K;0~Q!XD&QFV!BbY6z>es8JwlE;56zR-(bh0sNim==2&K z?p9NEw-IiT>6RlSKvy3e#XdMXg86IpLHcdH@%;qj`+vbABGNY{UPy8J68mPVyKe?f z-%RsGEj82KoiW2=_FBIq&T|Qaa7l%3NQ2=zqv4S?(GD3!TI*CY zl|%p4lg;Tp13lSo7K2J-C4>x6HKwQJfzDVl$cz>EzDi_lLIJ#I#GM`L;tuTpA&hkO zxv%W7pi_N#BzRh*PLE)}MrU1IG+_jD~BGu>SYWZmtMp!t z+9m4g>OJnD%jrn@5#Ks}qbg?iCgP%)PNN+ZbE&bBb3q^DTr#5~_;OJLU8H?fPbAKw z?sV_Q3w9&!2&+pqBhzVJS@3mFv&eE`$BNg)oMuhW0IQ0K-H;lwj1^cJH561u=ukgV zbm6GJRqZN8E>8D$Sw%#xo1vMv>Q3(i^$|K@pgIgs9IOGc7{I=IzZ09B?%rWGyyDa< zE#AGbNih2%ekX`aR6(2*R7&SCK_!||f=c(mr=}CvMkgjVH$JK&gSwHmKSXxNzGQEV zm56N;6V5S<4H7jLXREOoTOtgAqBb;~J&k^Up;j4P` zHKU5N%X<3oqDG@+&clJ|dH64jk)tQt^yrZJ46D?L3<;I9qeJCxf{kqdb~o{Fj!O!* zd3)$mXthDe_S9Y@L$>NPx!Pqh4LPSJk}*NCWO}(vMh%agYhCkLNV|=m*81q4r?Ukv zELtuSCevGsTs@-L=@Fb`T@z!e@lQCa@pH3bN+ICd&o$S{?nZ1+(PJfCHWC(~18^f% zM?&lmu^XvcbM60}Pj$z{R2nNl_cl0jO#iDh{mpgVpRY z6u!;^)74clPDLF}sJ`JklW;Z+r8}S_xu@Xht^^lBSNhTp!(AX( zhru4A+rQ0XQ~NTzlZzOkt2zdAkMb@Oct5v=;7N3$Vpoqk)A@s*OUkrs>pt4oac!(G zm2S=`P&P}pwotbe|y1;7yTWqowaz;tiQdftY52r>8vFS=Umy+Q8fqi0JBx|I32Xl zTDk(`tjcJLd8Am<(To8faNLGNy18YpN~7eQg$tNr>9+Y86p+UCH*{2YHj>7b%egJH zI+iYOAt7>0&*FS>Ik~h^0G0)Fz@AtHpNkeQXERI#wZ(|+aU9doW!td_L3E|}G>3$?Z4b8;Hq(s9Ln z+TxURqyi>dyQ(_kWa2__t+w_yu>}s*vSLolBJ#z5)MnvQoxv-%=eE#b{3i{=zi?Uw zS?YF5Jms)JH=RjB3zLLPn55rH;xSi&R?eQag!O{_(gkhM9BI^%xXa}WMKkcCS1y<( z6^I-Ho(N{{oCO`aicAs|#wFmnOIq4n=1^;Q8YJi#^JmRjyihxM#2%0>6?-EI601%s zHLlW^Qv|qb1>TAXUW6wvfx~~1reVg4^HdaI!}lkA0KvPY zF=nw$em=FMv$g~f} zku>10Ngo(j&V_SA003h`06@&VkMbtz(3ubb5N9$5rJ3zrNvDuA-2=u!Tc&%Gn(3Z! zGu=Do90|mmn9xK~dg=!%67FG?bVq{7Mo^Fz72UCzE4p)YIdgOeim2!g`MK>2XK_kl zFdB(W=`c}I9{|z8NMu5wx0rbw>^M1u3NbnS%(gKvRF7?H_4oN^7}J40_CD|O#wJfe zW_gYGm)G7~6%L2Jy&JPIaWu{IKkt2HO=Eamc;D+Ee>85q|6&yIHggh*fAv)sj`uE~ zOU#eFy&o5{Q>T%|dsnUlkkmi?$eXdQD%|9K#%inzZ}(o%*zKHJY>2c#rSQ1%>)-zN zcJI>0aCI18AGK|M*}`M(`3Ibs{=OsjKhEI!wWh%{1Q=g`Zu)<2ugB7>kU1O!-1Cx} zf;cusR?5gkO+jYS;$FzOhe~H)A{(=S<=FcVv1EqQW@35C zv(96C?^@I7{f$-Ch(wk5xP>XEyr%j{<@jo>Pj0=oG5h??%Bt#c#f0(gRhS93J#plG z{{85qN|~VI*TwsnZa=?qe06Ji&G?q^`pWQYetSB%ljRu@`lxjzm4J6kGwBhfAEfKoIBaOvZ`iI zO>Mu{39TpBj|;D#=gqoz{P>CMy{&Uwq0(B8!m2LV2>#>1vZTs;ah12U%6n0jw-_~7S&eymN|m=?m3LZIf3=|d-kP~@ zczDVHGtvJ~4$A({%Ro$-GSf!QqwZS>_E$XV$D7Fp?W5;rS7!p%z0Dd$Kf{!3PRK&gNTF&QR_S?!U=U|4JOopZP$b+W*%rhuiO*Bz&%O! z@4o*JIB@@cmq}lH@$f%$#F^)aGt9sLI7?8oe;3(Cne&$|l+5^zuDYaSG47J65z{r6 z0~0%zV*oc}Il8M^aRBNX%grFKcj%Cf8Os52kKd6r;I6S8(p@Cl<69FXWyRgdKm>I~avEC;a$I*gpL9I(h(&bl;XIpJn3cgi_ZiT{$Z9H>ZZ$|;F6 zpkt(t48>nDphJwj@&>-fs{>WZrB*7dFTuW#}$o4dYs+eiLk-lWH|EE?a6|HfB()3CId%hiTjbKtkJ zYU1o|*LgFs!zN1y{Dv$0v&g*G*7f6R!%Y?a>b;jXHnxU^u+KU>Jin^dKfIzkT#>ucjHJswOd({U!{v5w(D>VFP}{_np~_75p4;^m3aqP~eQd@NCME-W6RI(3_+a*Rg=)aWhH6mJ6{@-7 zGa%e+ZDeEOGeF!iStJeknIkepjxL-Np8*&Xp8?_u%1qLsGw~T9(UHc;SW z-rTvZm58;&Pk2)sk!oe?i8YOl)fF{7vi>GE<3Tw7K5y#W^C~K8TM%%En_9!(F^x6l zRki(U%4^p9hplhj?!S2bl{-EH>H2Xs-lgmIdXpdbPWOk}$|opv0cdatzW<|hA8Y#I z5BGZCvHY7GYq3qgwxR|cp9p*RuZ98=(DO*c6aRSphAUgo+4km{fNy19k@-#i?|S^@ zKllFxHm{;ujxy%PzlPPtHsLcK2^>5;77p*9FfM!#WMkp5t#w=Yy38xWm0VTSRAQ~L z{Ul4Cv+dIf<0@+I319iY*?ZgI$gcCwuQ@GqX^Mtrlg_d#s?^=l%K{v{G#W31F-cjC z?gr3Ir5^oOT zu0e5NsZJD&oQ$6n)3PdugqI;Aj^uiY~4OL^9RE_`xy+M=V@GnbYaheGIoPOcXJ`ZnH48{5T?{NdWA z60Seq|E{kiR=3>Paa z>u=))HnsYNw{PRh^!f5zZfzB&E!W3RM#zJtEC_WD%u=<4d5#V00< zFI`=ItN7Gp{R`+HU-~aX#k=htJhgHaUslB@eZ}JRS840qlM_3|C%32YeV)FAA~xQf z`rLH8cyM)k^9{7U7gigq)1NIjSBpRS`Aghdymj?E>r)duQ?F|n%gyQE#ZkFJ)i;ZGCe8QiYi4cv2S3t?9x{CY2O)a=GglA(HN zO-8A4@^1jBsU74?-jr8=oFtmqW2ly(!REuoa7d}|!=dIMH8pk5 z35V%TsVfd;--jmUbaXW2R4LL)u*yh?&)9Z2O)k;Ghqdis5_&JT9U2nolb3}<9u^K6 zlW-Umq+q+@{9W5_=*gg1iiU$?sSeI4lbTsJ(#e4;n3j~m3=*|TbQ4r48l_`rl<^nb z30FLg^3*dS@TgCTDn(BWnrblb1O`A;Jm~R&=yWPc%XzAemh)4O%#2@}T;Ie5BCX^L zzw({?&DE(1Gcs8C#iLU@2;0R=S4+3sPZfXaszqrOfBbhobDy}v@zP^|ule$%Vmq1> z#gA;SU7Fn8{pZCeeurCLe_PQI->IWp6rUt+aN_<;YqwT+KKmDQ=pn_QzB*YNzg>E! zT>NpOH-2fm*=!b%KL7gal&b&uRrG|p=C~|2m(YG*Xl<^pt`=YU{99Z{(>c0Y93dp* z>Rek7Au8n#8rkNQRk^=9Rexb_Hgj`&?JXMlc;@!v6GK~ZJJX8Uvv1h3H_V_i+~xx( zivQG<89ott|b9Se_PqocX|@dZ*Te% zU4Dn5f=$z<#mBeDElt2rF^Mh|-h|k`FRRTDSH67L^7CK5mhe|LLh(Jw?%!|kzK2)- zkmEyqvY1UVPPbyhl2cUM^Jgvp@Yal=#Mz*r1pm$oN+IO{6Ev(n)X2z8oY@8MSj_2w z;|e8NIVm}&e7Kb4gp_bCm6^D~H#SHvlw`z}aG2H$k_#ny7m^=tkcd`RNn<`80If@f z8;x5KZeWdB;U+8hFmO5HM$gDNuIMy81(|4waHB3!>Zp+UNq6KNS7=B!1(6oy@4m=_ zTz=$diqX|48-&}(T25?Pe)Ox4-v1hy){_pAE1vvI0cj_bI}6wF)%~4S@%8KlDAk@`t-9{K#+iL8)4QAW#lkjkKBXm$csf9QvU+?EVmeE3fNro-g0zpsK8D zJRD`>K@X1|q4EZih;^5x+ht*L%ec$>$nm>g!^09BvN!UY>>94q2e0AO$gSbJV{i@6 zh)O|zqgqCO<18z`>6!WLjg(|%w&a-dAfx3aHqJ8FQu&R-0r`!RjL;Si(|SREqa>Bz z=(YeiahO5QhIu0g={9jZ=1~IP&ZKivd9e4V4M^Xr>lvAi(||_?gonn2L#~EHq_1$8 z0fvU4L5ZhHAPeu+%d;|Gy__Xpy&Pwd(r`#=7-$h|0EsBhf<(F$P#=yHYkGnlC0BK0 z4m|P&-V-Ld%&7B$$!$3($zK?Rl6Y~zh4|<*sFD|xEy-fI&g;T08B|G)2oAvR*kh>f zByj+Cr>O(*;JMnFVyNzF;sDI)LqS(5z@2oy*cS5h_kJGv`Rzv@DUCND`x|e4=hF0> zI~xEYAULIoslSgo{JxMA6P&-ZbAM~DJy!hU=O&*bWDghG9VBI!?h5+__!c+Ae-j$r|6>`Qn&Rq1n~q$yba2 z?j*??i~sfKuKxA0()i5g_>ATJc=W0=hg_I^bZ6%~q)eHZDn9$wVtumsEV)81lpZNw z{hi`GA%Rz4DE?ky5-)(`$+vdC07&-ntHpm*m@NK7vY+_hshuy@r$}^yN&086u1;Ti z3o-xRzbyWzpWEgI#lJ}Y$fRBT&X)kecI5TEGgCbI{A15Q_WaJye6jsiv)#Y>((jr* z`@5zV{9oU%S}(_rH*Imlle=YtQED*^y>vX`2Z2|>&txoXKk zqIfC?wM7rggw3U@3f+-aGO}=E)|SfC9~N#zhI%h>BMk|v3NOp(CwxU#KjCyhKcOV6 zlO)HKXY>;unmNl{OZ5{92lNw4GD=A}OzQ>xgp$0bFiaI0sSmFOq5S>mX< z-Ksq3CusxHx9WOEKjAc}9Xur*W=a{RP#TmGBzQzCD-Bj^&TZViF2em8U4*kl7vVUg zfP_Oz!z2_123;h3OqHx&!X>AIBnPSxW{OuTtV3v;$`hR;J>iPi3iTp7#WVVe z#Iy~b9cFSyo6sABHsOxFHsMYZZNiz*hzwe`&whCa5kA zVto@0;&+PV+9eC%Pfh}>BhM3Lw>gcc>{5BPp_A59dFp%elYQ%NqXbM4Fj#t~^d`=^ z_lqC6x{BBD-R-6F=cXH%-kL70a#H-s?Kg}6&u1TtaIRfxlH(muRHgVs9^bvnBTHXf zZOgTEd}8YDx9;;o?70(D|JhXWXa4ZX`jf?PeD3PcEKg2jBmU0n*NXqi=f3)6;|`DD zoVL6?UK*RbSsK63>$wx3{lJ@>%e~8K8AAT15f?1uh6JS(u z$FCRHT;h8+6mbRlfEGaxmiDJXyLuKDA2NrSGeM zQTRi9m%3+l_06?6-!9$?-_d$QF2==wM0(`XDj6hOmnNFyQ@fX@zIOlq7ys7_A0T7O zFIZILBar9!Wgj0R+q?$>^81xp-@SzXt`(8LVw%=pevkf0=lM&CK>N{_Sns@D-Vmnr z?m5K2Z90!OX+a7w$!6GY5KjF;UPyHwPI5ZWIl7KS@E~b%95f@7lpa>+Nw<&*PeO({ zN4w!0GTKl^twCmEadKt^*P@K$;)8V_+MUsPGQwv@qo7V!qu_Kvqo5?wA|yQz_wwaR zMx)@KaF%KmdQ-Z))G+av8i|OX)>di8qf=d&2@j-uoYBcCyOPN1D~))@T=cM-9Iwh6 zopc(WGF+3RM$YJ@J90)R8e*D=8@~aKirPVqqW{7nrM_O!sPvXZR;Ff9o-&8&O?hAA zVBJyGpfRO&)2C8q?Myf22nrE*hC?ca!}p{yaeqc*;w;gaI1XwO?+b^N4(LCWB(w4d zt^e@sA^MNr81x@^{N6m$^ZJi_QZlBTz8n3A>e7GS-berWO7RhCDka2l(iKWg*_WDf zd$oL*`F^pgc7^&MWe zGci$GT|*loJ>ub{`@1`Cr^l1UpO~Eb&)+mZsN#;fAHRf6!)1z}){*_Wq$B%dr!zVo z)1P5SYr0_0xaLr6N9iAXm6R#jitb)5e)6%%s~EKKZqS!F-f(ITfuY5pGMz&i9-XeF zqZ8|x=I!GDoT_2})n}=A8#SaPFXy{>{3--<>gBN+^^^X$IyFTK7gQO(oA1TJYxS|a zxHdPh-Y?E>ua;NHE3+nL2~XqcTcy?2w^oaXT>F5(_TLq_NQC73C-JjJlX|;!vrLd9 zuG&9O`uL4;=U-uCL7v&AL5)wHaY((B``RrFkL`E73b z18ynb`irUJgzJE*39nuKiPNs8FYQd=NEM|I5Ee z3Kw1*dEzGuPl?v}r(MrJ!0+P7WA`uohmRE4{@DIKNBOvwf8hT6UN63py>^>x-x#`M`$@_FmfX`h_HCkq z{$p>v?+e8*>b_z9^d;J({T^Pk`bj^nj6_Ex8XMiCIv*Z$eW7>je4O(V$2H$3^{2`| zN%^Narq7eHQ@eESZLa;6UCXyiW3B6l&lC!O#_!_DhhP8kHy-=KU;E;tU;44X^}fGd z{5!OMab)GfXCEK=@Z$UJy{dnM8^8O$bL)RSS{(Uybm7Qu3g59p=2o>;=UJN6`LDtR zm8v^@x6ThaUpc4#H@U7%u%eNO|8)L)oPV3+49#8m^tb*8kyTRX@0O`x-|6Y7Hc~o# zeB=o}Ev++CDD>QOLO*VQ>mPsfzvnRphRfddr_{M^b)HH`xi+%Wd3@xl#rIzu(O5;k zZgaL!Sg^XuxZDWO6K$#OuT$s5)d}nN$C>`Q>ANSX^9}0MT%GXkzYy9wIBt4w6B6^61&1GHxXIyvuAos2X(K!QX{jGYRzQVkDM17XyE42K=>yM8-ZDXT3 zrn*l(TPWPJwuN`@<=%OZ>tD0$xp%HWe|lx|jZZ)K;ClK_z3&^;({VWeCg&ROaQ@E* zuK&rv_3sW`|JMW8pLjn1{HHn3K7VxJ`s~2@#|O@v1Lrpe&TkEz9}b+q#(DPrUmm#r z6@UGMzJGq5^HCeSWUfaSULScPT>tjRLO=WQiY~y;)BZdBId}YF|Gd{Y|22*mM{?sg zy649)^7WqnIP_=r0v+78`LNEz!`S>9bwrQh{ObefzcFzBTLb5BbDr&sKj2)?iug~o z@kgA0nPb0hLB6z-IT_lJ<-g)hPth1<-uO-HuOVwdZRGVIuZ?`^$1hwno_^t$TMtJ4 zy-!sOgb*w2zngtt&3X!cVvkGe zJ+Z>~4b-Cxl6p^ZP3`+K^=@z+*5*+Dr<9M|{Z8HrIc(NH=i`+3tUo{a z`d@qF(J%bi7vJ}#;@`5h_`8qjgFi?M?QhTihWmc?D(^n`K36w;-_!nmf3!;b)AlWW zi`8z_U;A^e{RYRiAbZtDK7Q4{9lE9muF>(KKflr}6uxKA$SyU#ZTMphWQwi)hP5FX`=ybm zFSKm%^$uU}52&a1gud7FbpM}HPBZNLb^hm^f79wkuRr$2U;DzNU;MEzz3*=o|F(@r z>B1*RqV$=+xgOSfoBP%;dd8no{>S!=T)!-hMD!saBc7ys-+Up^W3HabvAW*t1fG?@ zuJPCP?{WS2>^*1Ny26^Z^7u%!`2L#vt9J8$yYIKU;knWM$MO_c2+!{I!n23)hn10% zo{o&j)Ae`c!{M8r>Ic4=Z*zF}Zzk8zzFXs??`mF4=8xp?&bJWi!Z_Z`U$ZgQJzvk4 z+dbiV-{u-qlCe){B)RYD>xII{-L)VCCH-`RYnm6_7p|=b`6#sKSE%Ej?PwsB|32k4 zyVsQmdVAuAduBMF<^1=k7tX)Ox#%(CKYiD~=KOmcd))&$k;z(n|DJwyPj*h|{JWUh z6yBs~s4Y7GSDZ&22mK|KKmCcIXSp_N3|0S-@?YoJ^R=VLH2};(%{g6v8u!m{aGdFv z*5j^YOhyXN|2Fk>Pk8TOdn2xW4MAJ(q1>o<8jh}=UZX(y7w_esp?p^o?_H3g| z)!*BK2k|Y7BWKo*60$NYhoddk{rYw)hv@t_{JHu}=fB1I9>+^5z1#TdTC`Ir{DED| z$wLblnoc0ncdFi>Q|~#em(B;3kKWFghj-qhyp+~&iPXZiU*+1uIoJLmd0sL%llvaq zb^HUm6aQ#tpE>)0YoC6=wJ$&5+Bdi++VbyP&%W=^A8;*tDc2|V?V%q(nZK5d_g5%? zg7ID&9B=f|3oN@D@KM^LKL7g5jy70$2Itk{NQw28FY~bG29J zU*~+B`??kKi%)?y&+w)ZZN0fis`Z%|SAqjbD1ieu*NodQ$(QrD|vktkI znGXql>)LN5*U~-@&-^p44VxFb@9E>S*ECkTwvxYQ{72>YD9^OR=vC#vMY%AZA@ua= z3!gT6l5`GPt&e<=cZjxh-*cx!`j~ONuw(L8_*M00Rv^DGxDc3YO)Vfi*R9YxqY0|L1`|PDf z*J<+(yvxy3nnz#n&73WVcu8^}7*QGpB{6Mtiy5YhQ0MlnYl%Glj;|QrusU z+)tstSgEabm!r$Gw4vMhM7_Nfue%P4tL;{;((85NUNl>%EXAE0o%L!&XV?MtJ=LvL zx^cI?)brn<9y{KR@d-LPJ&xkz-R<42y<5kV9PMo0-n%uKTr9-&u^W?Xm*Ylro&Ihw zF$&9Zv(f4;H7m>A=ppK;DP1>&YYn5?$x?r1m14f6eLaffjT0>0H&0Kt=vEQb{sA_z zgID5sjDhJ^;~VYudMmzB?Z?;X*hae*4K3w~YE*o^)95u?%XDd}G+XLZe0$^WmOgOn z?$-VZBsxu5ZLygd?9tI%2d6jpw#Len<#K6ucD^)wr94-fnVy;6nwXw%juqfx;V9UvZ)=CFu1>b%v9r(DvdV1*zNJN zR=Hu{lP@ZCS2{g+Ee?lJR~#Q7lU5==flF*-ExZ*K>do>B^L=hwZr%rnTl=wh5ZF98 z+S2Ukx4P@JwS+6>QGDm*G}15solfeHO8BJpPP^BRD=SfYSm-vEZ!C2`5tZk7FRTFe zRUh5l-?+0i79|Dch!N{|nG?;*V!au!cj`+_<9IxBHT9HAvjZQQE!5ZQwMKuf_aYrR zU7mHb^=cccSnjkT`*JC1$x3^@z2564&GF}j`i)xsn)N%qSgSWHFZLR1ygc+`zDT3v zm~Xe=y*3j!>&unui^euYEY`vCbSbXiSf_AifyTnydTW)=s+*B>h5eI*+sC8#^u;%i zU)eZ}r{^P13(VtIkIBa?_P4ff#qw%^w2}|#R(s52->*6;bh~k_(XA{t>rr~BL2JsF zc(ggbJ-$DF3kF3I3~T>jf9v3Ae|L{7qxX7pQ)8%EO%L%i1L zLYK5E$C&8u88MOdey<8az`BYXinekK`}w`q;R}*H;mrthKwn4pTsk zggd%Rjb>FH5!W^`gSKQ}isS6G6~o7L55 zK|R=p_B(Zm>RP=98;4Z1h;{1CdZk;BE;dg$qPfZG$+?RKP0Dz&zZA`uuFS)Hn{lI4 zt3>5_oy48$wPyQzrROKABL#89UbAao(23it@Xt6t++_&UNu}4-Th|($cB|2<)o(NQV=i~UBk#t^j{Yn5hf z>u6mKxyY>TcO7eBL0Im@T4_JQXnN)_SeQO?t&cdNN3D*oX$<|FT(K4jm|?r+-bR)2 zh;OLFj_ciMdM3Z<#;f%gyY|ZI@`8H25wF$PqQjG;Tf5ua@rkCgF+ttPqEcNok)YaM zTSFXCd!tctr-SWi^mJbi6Y!_w+XqJ{5yF9(d3K41FrcJP4C*2(r-rS&5Gh4a#t!g8x0RioL-g~=H>$Mh`BemWY(gYF2oqK#vi z)Wn^Qqs`mT<3V@#^27$GC#U;c&%+l_w(d=AT%q7}6St~O4z>}7P9`>P?mmBfuzjLC zIo#Md+&rEzzeSZC-Qn-a-tok(-3_I9d>&~nVzZiCH)o=W_A&pJqlxXqU7ojnclUVr z=I-9^$*a%b-X%JI9|G4PY1Xh%_?2~TvGEAd{$#7igS63>I8IE?7!)Ky$bV=i$d2=~=vvqf;CxL11GUM8-bfC6)cV=N; z3l3~{y|P?)!yC@jngUN~^&!2+n!aa6oDe|_(h-4smO45yKRsKv8BnXlUWA(|7wVm* z)kd=k36{C7y55hw^`23X&2|_|ZLQK>6~mK6uzd@O`1s|qXgYfCIZ7!0NEFAdrJDK@ z%Br{8y~QTIJ6EWxo8c7|2xzU2oK!&=i?oCxy`+4qJIJS&`05;Q417`V$46;1KHZnh zxOHnxP0FxD+$Zj`d>$Uaq(59Tbmxr_*Z3i?C3Q7L&Q!tVQ}+Y1ZsH zO|k0PxLT>M)HS+w8xcKn=oQBzdYukG&cSSSbW<|6XMoW!M;p;++){UV zda`+Y<7jkod~+OJ>d zdG@vJ>GXU!73tYM&po$bWlbd5q)_vr-dwWTUWd!J+KBR%XhKA)E=SB4b#fhx2>;}eWvkNoxv#?6$Mfb&Sug>=~d^WE-HUZC+7T|RZ&9ycvT6%~K>F8N}vsvjN>kNEZ z@49^z0~9l_cJ>Z#Zb%$Fwwa?M)7~gCC4afuUaT~`Ca@s39c$#`zQk0?O}+V9lhJtM z-ogHk`!g_ynl-2ex<$2w0Ac!lCyT|2n3@nsBC4A7I!HKh=!AOeh$MA-bb6XTGYOy^ z1BY0DNxr#q1vNP=TTFm(Z0b&qDXSGo#?E6hC0=udRwtO4j7l%*t>^UQF=;^8D=nwI z%@wRW^wv@Jiw;;F`&u3yar6+TUx+RXWS|0LANov8Cfs7z96?a8_Ci?L<|P+NvD8d# zw3d+bdO_RpTH*kBGdoI7{57QU0c_(k2pQ? zv6H)y`KILP(VNMs=|bT$%jjmrElC9xNKeW=AX`D#H8q%Z%!#b9GP7W^%2I7W9C31M zx4u?cUumP5WYDQ)!}fRxVl3=IU6!gD?qapy?X}keYj%ngs|s=x629>%S61o3#h_KB zDWNP0q{NJ@0TeJ4P?glLdSy-eQoV=7GhZ-_Evuo?zW;eaoaI%lGQq&29k9Ir2SV}yk2>N?tc&**Eg&<`_9xks!t z&SEdEn%Bv$BV~vDq9?2%D)lI$?x8A+@Q|?ABk9)C0+PR{=qr(WptJDq3l` zt%x4&C5r|Oo!&J(NW3O{lF0D=S}MbH%!-dr4blV}*y;hgL0hyU9Wpg#u`fKfQ)#xM z^iZ@%eN)79j9sc)TwCr`)&L;Gp)u3O{>j$P))99uN$SWT175zR{}Neu;$v}q=K$bo zZ)4{eMOQ2Yyp0>jtW#cW)Db8h1L}dMLfl@T6w%~LO#ep+1xs$Pqr1}p^hL?|XplQL zYRMO9wL6T0$|XmkNaen$DUTgNonvsh+xUDGSUG8emf81u|!8V64~ z(&Ef36*dzZIkYiT4{i)k={j*noCi^VqBJ?T(s6$sTe_C2Dg77vm6{EypDb~wa@}-q z^rZ|N>gS#brrlrZ6uR~Ls@MeBU!!HZIz;GT2amXA=LW!qn-$yJV+G*u?u%>a0INu+ zOYj7cTFecl60@KS5Qt_vAcnbF-i=!*@>mfZOUv*=$HatyfX)iCSz@_cuth%LRt51P z)D8r0;34sg9_y!IM_Z{q_d#|L1ciKTQwq|`l^9BKoz;u>U8^8Sq6uIW;jt!O1r-%G z3mhjI+kmlswEUN|2$07rx+`_5sYb6a^cz4P(&5GCO;$1?M$^?A36LWM-OMSK&Kh3> zF0urDQ{4i4cmblOpRq{gVe)bazHy_s*nJV`N?Z~f!m3C#nl*{EvcBG|_bTvvE&t&} zoYKKvGn#?yVV?XRWns^~`MX><=1kCLHX>^g4FPCK3DLXsqBh{dDxvF+~7_ATy=o6cc&IR^WQG zl)wrS6Oe`J0tVRvM6gSIp3;)Nw=)uWioXGf5@2tgeBw zz;5|iZ(PlqT@yG|BF#rXYEn(s^18qf1;gvK46j&R9r$vu>=k(Q!eyu(bOY>{C68~* z7uk$3a+!{qhQffrx!YB%I;7moL(u||t@Pu7*qZe+Iiq95HV`hP7zok8bkteHB#;q$ zbG8b9A!Ai39M2oZj$j+dyZiI;=_E^XC`-G3xw9S?7B5zp=cLJHM%j%F7$Ixp4G>Q4^-$~)#-O3ba{U@>VM{zE9CDvDC{VSq`o#q|i9j{igbu%fn#w|FKc$3D>yD0^Bb`B zq+rbYDl70(o2iE783x&k{BI(EFIGC8hE!En3hWB*%cF^Dw*>WNGH_rhz2m8UpPV#U z>z($k)`1aA2WN63aYH;UP+Dj9wj&cKy|FiDMT_Q2h?NZeNh>}XZH;Tx#v+9*BaOz3H#a>$ zJqHLy3&ecjJ5}J#Xp?gj0vLWnIQm${C|mDTme*vha#9C;xhHNU!8lc$hk-E~VOaZO zvoBjmZ$*nua$-PWeQh11zzjBMZ-s(ecUKxq7`Q~|m>z8MI4w&eR=ZQJN61a6t_VXs z*!O#aVu|1S>5;5a;`UCNNE9K>OTMnsMaWw)O=N%Tm6HuD z@S{x!Zf#Cx=eK;X)#^5kj^WZ`p^TNP!CZBKpEV&=8KWZuvtORQF~75kZLL-o-Vt|DdA2oKW4d> z42k8Zwu75SD0=Hi6K)(~ z%iJ~&PmgbJZlCUNp6nj%8zj9whIH$vV*=nCQaxr4ISx$8yX06IUFGM}-G#XlFNNm| zEm@>-i0JOSK>=HMJIL|PdGIsK(U-qkhWU^EQU`y4pXZ2nUi2x zSTj%o84p#=d7916C4#cKE6Bg6ykOMB!<=QqWK>!v4N@PS!=eTYB+Ue)vRvJAfMeo3 z$-3RFJ;-x1tzfT|yki}%19~p?A-H4dZ)jb%(D@C7OH2ltY}&nggf|pQf~^>62qtgC zmjORIc-ZAmB^gV^k&@GBTO;uP%tE5po`Eu&Mz_gY<`{JfR;R;lrY6a6HWTrtHQhdf z=`Usd84|jSrmrCLVwcdg6z~XP8?=qkkXzlra?s~wt!ymY%+xBtKfJK?c5pA54-h`Y zg@L3T<34&dNSfl=cQ^J<5j~w9wNqb4=_hSUL$G8Dy>R%o9EJdE=;{;Rv&uf|~+ zke98BPxsBsmLs3?C8?39Rv7=PIJv=GM(-Z%-V#?dxlO&hkZK+3xfJ~vLhv~z=$hPJ z>04LEK$4Y3ErxF0=E-Jw^za=LUsA$k*V|p^)_@;@1ZuX%&RPdEg$z^aihPA0OT!$jbyv%f*x{mo5A+4* z0uHth24b*~s!<>Z1ZUa68_v^H7nj;f4M5d=YCG;uuqk175-oWbu?F4Vs=24QLnNWb zqCm1}fx$;+s+!lTf3!^fr)QmJdy8!pJb8N*k!wkCcZ{c1zb<*Cbk8vzEd;PKB#g-a(h%$!ZZ@vV>R7#U1@|^p!VKhp zsnktOX;B>i;^_tsze)GtNe5=of{e^xB1jts7Gv~JfMa*e!^G0>9G<+2yegq~xHzmt z)dFUzPIw9uv1&eRZgN_z=#IE$w)N<_=cDo%ZgN&r;x7x5B4`Lt8CoBI2 z#;Tdvg8gO1M3|fQ@yWr_#ts_DC6=r3u+(&XUUjEgFhjlEDQ05ws`)Z8;e$O=ZsG+# z8LuE;l~X6#hUk^x=OE@|hJ-WX)tS-)VL3LQX~53WiN)&d?m#LW@mDp>P$ds|*q2O$ zYD#M3$ZGA((BxVI{mEl#2=wQQ$D`na0R-145=WK|vuf!&STNJ46Svlb7(EQ*%*o{@ zMB~hfOFVLF=fzm-bQQbyc^A?aOPYi|wYq?9sksLKN4S_4gVC563p<(sX3qEqFlUbA zjXj*x1s}^dztsB}IHnb@WQPJTr5-T$-6*n47(Pd2XR}*~sFI zcOs7LIsVQWEnlk1ucz1b{K9@j>D#xCowlp73vz^h6QzDF6H3Cddf{xqP2@Rho}Y?y zX9&O(s(BivS}`4FHiV25B2u#ulg84E4xU4ogN4L^JWLznQa>aDsV@I^~&6Nd^ zaAesg{&l>nn?#(L!sk6?5%!6!;c}`s*~sH}9UK1;&r7d4^(m?0Sd4j(I7b&P+OENU zp7}y{f|~)L!!nUFG4Kz<5Qs)N8cPfP7+K7dTk?WJ3LY-Q_O0C`LS#6&X!e)ul?GP- zrrBWpvBea2JJn7PoJVl@4Li{Y5bomjevOt933{CU(%_uZx7Y^1P8f75oJoUeFK!DjG`nbHEmc*Z$RMh-mnOo`;o#8JZB|9AHfvevy! z#H;jA0tMFAff{149mom4#07{=PKqwjlkZ4R(%uvwau(+xlAE8C<6!cEqN-Uk9W5$8 zOo6mwc(_<%yIGG2e)0>11`mxqNFOG1#dS0Zs`pmf68oi5s9NgtFc8QffAS^bj6qQ+ z1R2Qb+H2+0lb5etp1(p+(M6fvrh8%Zhbwv_$-yAJ_avT;~ANC$vMiRS`g!HGM~gL^b&oQLIg6r2%>i4RLd$l zms{JsNo6{q%j5>b!jSa{7~Pi7jD;8B5s#I7|RFf)+ZB|I!Ra z*3HmsOg%9$&pPn~*~mV^mLU^7tpDJ0;eUZvcV-pMZNG48s+*|mjK7Iv^N=#0 zxRckm6CU9_@S{=lQ_fH!A*PTDdi!F38E*&8CtFeADQOhKbbVsJwq%pFXU;9KCF71# zmInCa_6DJ9QaW@k!7Mx1P5aBJ0O+2-YzBL0wjcU8`V0YKiA5$V5u|U z=0qG>cQ_TVN91b!B-_NlSf1P=tY#l3goJz0x6alvn zj!%v!w|?<-_bzt!T?;8c0tH6e4p|y3PC`R)vU`h0IzO8ztHQ7@bO^}o8P+Bmk-H6? z?V)rTC7i%&eOcg6tG6<`y@_;xR)EVSXo#p%aQNlu_N{Sr88Z$_+c7T)6-K@^>FH~P zWNO+=M(eOKZ3sCE}Hxis@sq;=&{xksYUR6$r50KjJot3 zdEgWu!+iD*kW)zzQYe^ha%sz-GWuGqgZ~*$D^4nwV|J%6ffPn4=^{wqAtL``irKAW zaw*+oknJB&6keR+JCoB_%B3si1>CDjmlvkXb6XRamkP|pYqNlCU;<9nS}63hF1xte zCa0`j&g}DI_Zt39uD*eU)=Nak;3D8BxFR?O(U|+8^FZ)ET+k_xF_<$0h=?Is(ifK| zK#mDuiKVih>{fCE%VmQU+aj}r^DsAH9^p5b0zoDXbAck{SIhdaDp%?-FU7ith<8bn z7h8XY5}B@ZLoQCKqN7v#)jJ8?**!cKho`ppW$-p#n<~SLgF!?gvfhrup*_RB(b}GQ zrJc(<(!?_uso%wr5{~F%NR?11DUB$8?KN3X;=@g>m9nnk#U-*4Q|{Dza_O@5$^$6O zY5FhqNpQXh9cxdk858E|tk3>f!_Q(K48^zvm|_Iou|@=KR|6?Y-3BIR3Dc_aB?t?(!W7_Z7Nzx1lK#33lnqDr#^{BKjf-un$o%L>!Jos3+vZ_$Z@f2>cLvl zy(f})Ksw_mk;TAx)Xn3&@_)X0d=JeVb=U*Gc%%VlVo*yQnhw<%s*z>F?h>x+UzOBR z?3b(btiyo^Ym!zZePXt@RdhZSBG1Gl(&+P@6{=j1W3(S$iba6rPZL%dj;99|$7dAz6$RnCKd4GaszLVF};B{mJ=R-p-8vG@e zqk(f?p+rhcA@@nGy^cY}Bt&F#VtL$f#S6noZr6) zUO_Kmj^AFGDajM)?6)eWqthCK+$I;e$)&D3<7;i1VPG5Cw~Ak6&dC^3yB5uxvxQS} zs?Ak`bXJvyO8$|o&HzoTw4pB70e|FXZbnVhV>4=-q_I>$lYLDQf8t;kJ!T*$;R{e> znEJyms2?pr(j$l#C6aUz0Tc>|S6nU0vq&-K)1fdH;_bv918cgtbf>cf?PI=BFSD9r zsZxssO8{;ww-i541v{rayE30ioRwdhhg?nv*GVG7Z6%iKWdON5dR2PP=trRfaaHSB zAaax`MW)Jy^I~>iqWE@XYdD&oT(+HYRPjuazDoz@^UCxW=Bc$YAW7bQtmsQ|cQ`)S z5bPafMCS)LUvlS>p(2a~3R8n+`wBpp!1R>2JYcSHTTq||mW2QSx#dBgYRL=a7@hUr z!AYwuZ67DA>I!}&45QP{5if=n@~jr?h*0``5FdKF_f)gK4L0Ch)M1*Y#Kg39Lg%sC z&U#>0IxzFciHm-PmZ2bFc{OjUX%p<1@=5kRk&7*6td->;Hs5*4rBnoc0)*7?8A z&pOmKoVi%wObWl?t|5pD_g6mc+ys6~kLSWo&aEZ0<2%c^u666I5Bd8|g`mjQ})^KVpJI-oN!9YH+0kGB~q2^)hP#G;c#8OE@avqCnvhT}K6d>i)t za-KDxpM3nfitrj#n1VdJI`tQ#g)2TegN#|DCwJxfYd>jjhA2J9f0twpE>r`+=3xx? zyNB_e<8$ryzJJVIf3CGYRB|5GfF%OzakI##Ih29?bgOW4YkroDenVKKlOY6SK{Mo3 zbHbF{4^N1=GmwpbG+HxSOO5Kma^WOF5<#T4nSo?@L7rs+1$^Q~<`y9%pQ(vM{do`lLi8U!gNrklL-) zAg6-!d3@!Rkb7s>AmYboC=;kFIb?`8l3y88Q9NeB^=iU(QxlNu9rd%U7}jSY#1_LP z2R%g;q#1AgM}T~LWT7wNLOQC1QTQ8Y4{!?*e7r*5Ccd7p(;1SeJqc(1*1S1R%E~2z zGl)r$=>z{45GNxVH&POnVJM(!VhHZgb(vY1dA>ZKBO)X~_gPUC?hGU9t&rd)gg)B1 zEg^cFx2^fNGahIiIZ?%H*FwyLHnO|H=Q}4-<-Ra>VoFUKx~SgD=S(tQUg?Qcd6FUX z8KbPEOu2`ee*(&wQS`jTMhQ8`hg+LTibe-Oc|P7msuNcXxOzZif=@&y$0+giEC3!v z%HmgDglD|8W+qD$N1M|!YMK4QBz_l^A~D$L*rom)nuW~n>9>{%nle{`veA9YEL{9) z5>yZd!T5PTmz3k``7#=nnVTW;Rn{TYCzlTTQhJIC*N~5&GjQQKD7z!oaB(xdge4h| z8BZh~^iP+@6=?eQ!JVzCmv-)K>`noVyhP%|DM1srjt&k^rU==_W<{Oj6D9VXy1BbQ z^}rpACs0CikbpAa-I4FL49*S)m4)9?ADW4DtprWg^31$zUt6-3+8t`BV0R?oaqh#G z+0;uP&RfMvB67AFmcK-|4)An^)-n|Y4I+Cu&aN0wvDM*k5tN%v3^?$z=cCWUGK@Ol zD6fS>do^ODlK)z$Kly8WN-u-vprjoSjoee!sZ{|RPhIexjqHVPB*BNMxr-k;zKA>$ zz>doGD06INFMXTmIV+stO6LFzWM_soJGDb5(C$)orqaLBXf{Y+DFZk`2|-V>2!(LM8}+G446(*W?9Gvjx>0@SoKH2$qlE=a zLopg}Be{TUTUI)b!_wzeF$dym^&{UN0vb~SQJV}5QvW^1Ha#z?fl(X?drIIu=ZNpz zE`Ok)9>JEpR>keq@d$abFnG!RMX$bUrMGR!M0);>Ou>;n7C~A zIF?;Gih@lj{Yi%<05-Dm(KRsnCgmGuA zsWq7N(J6;sM%9eg*9P@$0bnXESesFOl2A++~qvtZ(yOuE(-~4mY=rgb)zqp2r z2gjE#k!?h`F`z#ifrPmme8OC>>!&wL-4|7|nxfD21as43%fM^eg`+|}PlRcdGK?OD zzc6M4^nA7`QwyWntc|O?Nv9$PzCA41zo$Z&A878%vo$ zgFb-;u{y%seY!qntu&y?h;cMnAuX|OGg4+-^eHEt%fT7p)-+R-&jBX1>5gS9y3SWy zjNXj*Qn&n7wK}U;I)UU*vE+dr_6sqDM}6er>aev@kjEt}Arz&i4Zc2;E?2BKNfVuH zLSZE-ca&ykKr}@U=`2Zn$15AJ9>Yw@>bDh%tNMe~O&!ZV56o3`8_u|8D1Eh*d#3iIhX0fvBn3FFX?E)ROEp2+#!Xm4BfiGPk=ysxh0L54LV%2iG&+ zSAqMO%^Ch|S?~g{uw;D${?UYg%+ByjnL@*p6!_t4rpJ7PCV?5Y0%TidTl*5r==$a z#6bgjeX0bH(y%~cDP&q*Z`2rKYM8KqBQD$EbfX7dR6B04aT|E3GRMWZv=SeJR_?>f zp-K|r5m8N|)p}*A)%F;BbVZl~Qw5(mZE50Ro#4)#1+W;cl|&Ag6zg_h@*)ufk{!)l z(rrG2P;9rtCi3i^-OZzen|m8F3>sS|K}+|P9O;sToxffV-|ux zV+!t>go(LgS_xYsSRHRlh1AFp2!kOwI^M(^^bVfBS42TEcCMRSM`cK6bk{b7!jIy4 zqaf1iqgQqaPBPIaN)OcqX$)KfN%0I_5pfK;YDqm^6{B=TEiyl$xV|H09K9vLu~~!N0^RnR7FmD(!0zp7&xHdI?F_C<|qk?6@UsEqmlyGN`=e z)|c`K1o7H+{5NZ4FdFG{geG9F z2p@T*LylDObbAz}XSP9ec)|1s4BtadRw^ql*&dx9k5P7u_$u4-Fi1p#$h*oq6Wa|< zAXk@M6D4su9|!4-meY(NbsV%6el6aXCN#TsfF0Ipv=J)9vzg;N8|ItqZyAfG61^6k zBshloRA)Y)88R~&%#0!ivYI^`5dbT#VwbBVR?xw7`pa9MjV@i{$Q*pRo%CnBNe%{| zvw`pMd3PB4PLKF9bFefSBkV-ST=s4w;#@g><3wbG4NW~E ztVAo#VrO-|=T;g!4EQn7Sy@9ZahIrjC+?aClo5Z^j$-WLqZ84L4FfY7Wr(pQE4$HI zLe*M@bHchyu9V8kQYTrYd^Ql$M**cMtt&|b*+5l07Ws({qCj8C@{W+NTS~T#Ao0+Z zD#C^$O)NdA9!*4@0%zp6k63K~_V_fhS@T@HqA!(EFyO`hB1Kt4hjRSD>vb`+PIU1Y zE*vuoyE_|}7%)=gjz4B|Qj4RX%vQ)hphvzW?Lh6}1KTD-fcusI$aBa;5aay~Q zm`>MBc3mLLW7^8}oa@BD^s#ZuP)U;rYOzgIMGnh^uaRO^YxhcG`nX&OIS4XY*qtGC zh&5YQQ6AOcS$NH9pm>jl`&KIt(M&G2L|396N&>qbytEf z4=J6cH$0RCW=6|QdfFJV_4p*TQ<-T^G;^Qg&JGUwO1`XYr}`A#;`7pC1(0hfnjK1K z<^)KT)T%_?8n^Y+x^mUF6H}3<>54L!YV~xhel|;qi%EA$;AB*@g~M2)nfzsBGUIA6 z3&2cLWJMg+MFph*5fx@;6=t24VGPYRK7_}Q%Me(p!k|d^Z2ojE$xH^<=m9vB7#NA# zZ5k4tKI@`gpE-WkZ6>luzwnYotiXkh<~pNjK(ZHN(?0TX@};p@;oaa99Q5)>uyegrYx z)L0p8qm7}Z>32$~3}Nin!Ol`ck_PsuHmTJ)QgMgNCy>>Ca{Xb(Wn+&*PRR0&$Q@NY z4;v2T`{aRvZmb`IUx)-I_KkKL=wPAYR9!{%=_nK6m+Z~hWLvJ(oljjCJciA8-?Hrr z@Ap39mN5z`&Bgwj4(Q&TEl?lG-K=hj##!hLM-v2XEk{j`yf8@32kqzkkoFuVUv^Jm z8W*fK-by2J16Ln%G@>bxZH-M_HE}}D3NIeY9KJq5whGap*LR^mcjP24q%1&kZMx|9 z*Z~-oEvKs7$0jUz<=A@?+4p8O`XGns`-hY#)RXZ9h_{b#?!8QYz$^@-`~3zVuK&Y{ zy)g;CFu~PFVg$$~#mT{B$SoPlZH6;MfdfVO3)qHH>K=88{8;D@erRS!aYD$Obz7)N z*PvnfU3a|cez35R3vkrS$c6wi=e&m`N2L>AxHE&S&62z$grWY@fhia6A#lNIm-k8p zUuGcRWLE;S^Qd|GeGF90Lu}mc+_dOd1!XWVZUEIX(GHvRhduqpXIU$szoW zWEvRL8Lt6?bzC;#PNxrqkjVxhf0jC168m2sp^2s^F}-I9yHpNU+j}zWz8v(i+L@;oKn|C~WK`O|nx-6Sg_JCV`6yfKS&u z%2MFh`rHCDbipM6O51)T4LQ#xqjyWVqg@++If?^rFHLlx6rJo*qFv8P!?`v3(d4$l zS`J_xpO!tG|E1WMS)wjK$V_$4Mep#dm0MF&sR*H6CDD-P7!HD1>>bawg%g&mV1vU* zia{xwM=oRj2$prm1)Fi{sWXj`de8t*Z{-^YS;<)f-Svze&}s}tU2GY$)yIvCH^86G z5iExnKmxZru#1zC`;d1Y8V#BCW+$)AmgeW?XXh3W^=9Yilv%Gli=Rl=N9)?G!xAd+FZ5?+`x#4$aEt%s9 zY=tc~&B^{QQbHPl<0hv z%t9)jV4pcqMn8GU-3+N-2sRZcS@Q{BhV!CsT_Z493GrBuo$@72t}fA@6+7{oAW)A~ z2B;f&BamJ*0~-XL*Pt=~ z2xA%SRxyn%mC&BnMpR(sJjkBV1P>k%ZCO{U3Auf{rXW}1ePCfX;0l@yF7#6lS_qqL zRRYK=cg zGA&S=waeoW+$UEWwpLe{Uv@gBsiTJH%h4fiRG<>?jW~e4p2b}p zw29BgVC`$hB8`=Xv%r)*qfGbOG7Tz`u`obXmL)+?h&uYcOw2ID>^3C8>}Py75_2@P z3ky`WvaSutkbXoba3-u=2l)DAdo=8q;8XEXkH}Um?U?@l&D!SbqeKi^laC50KLeK9)5^FomB!S?9!*pxpq?+e@O zkYLte|4$E%QUnS{<~lp=e#+5B{^y)&`JODq)MfSbt|KIH_DOCMZ@x^bn_Zbpvz?Vh z7>I)mNeVfb`o}RB?G4hya&olwi?MUsRKckJK%a6g84o+qjJrasH8wu2*m0I}8P?^4 z)DK5y0Jq&}%(IK{^SsG1cJL%+>ORD!$9CrqNyjqf(I}tBYA3d%M`w;5j}B(MIr)KR zIG-DGI1&^RD=X94b>;@^rrf6FhNtIyjL@?+rtm)Nvc6mUSDCzKL4>AN!|;<7+R|W; zksEKx9mA50ajtDSGRInB5uX@P(kv5S%EXe2kRIms=bZ99?88z|3HM#;=;srD4x3EF zYw(tQpov4u#ofIaaawhjql5iz*c(2o^3yaHyr3@do$ow@T0R4tKo;%4qf`inxP+7R z2ALbl@Fn}9;+`w)3Ih&q6vA5G#RMHJ3tG-I=bojPxhdHoP8-!|%I+SMYi{cRghcb$ zy9egCu4CI1h?aH_Af_^;uTL!WflPI=&f}5i(Zze5JO55gg`NnR=8Td`nL4#LFll!- zHxEv6rS$vC?ra9(5W|YBBNFG5&&ay%MOQ4H6wVW(`q9*C;;rObaUfn0aIbMYCAo7z4`bkL);83uS0aOD2Nn<# zXeW^l&O>{Wn(ttR@k&R|h+>-<5t=v(&w;V)uW1duOMbD)fR-;lp@#uT(FnridfSxN z{Jk%dc(J}Jbl0GF6SkcP88T={&u6xP91I9yxJ29Day%9`*_Af1aVzZ)=Z|FDyDZ~8 zj~lzW@&~clsfK6U+2ILHd=0k?Zjjy9wvZ07a^~9L5?aqpH(f?+9cVr%jn2XTt>c{J z0Tisl$-6AmQ~yVtw-(duCoQbYc?V%Jq15WLTqxU*}0nuN0hK|wxfnt z(3cFQzUleCsLzXK0e=zdhKGf*`~8RC0|FIDWKCT5Uv_VT>R=QQ&Oyc%5*AX|__{VOuMiWJckh z^~PFq3&-3+pNi9WQ+L56j1m6j6Fj*riUyhm_cK&6oD9*pErGhc6mYaOPbdf3vEEHu_?7$vos+A<_x)WX5`Hi9Th zik>j;WY(+~Znz$~3X!j2+~X>FizTskNFksO%bbTi6xSM^9**iE6@@>g1qzr+*rjPu zBwISRNDTruG|#>ByZwNdDP+U2Ep8s*9U>62-s6nq^Y4TmG@%gNLGz4brftC&=1}b# zKC~F93>ypr5qrXewKGF%QF^GEZ`;M2tg6|jDW4dYId@Uf@spH~ zb(VS{%))+dZJca?o@dj*sYr59)+`obJ$335paTGlBZw|OH*5w-G7=5wJ9yztTP44= zXY&OB*V=BYGUMZ(jFZ#BF`+DMQOBWo#3o@XNtFOBeu+HrT*E=@EUPmM2PSotSM*iq zB|wl{lEWl*&?K!}ea+CuG<8oFq00ky(uxTDbrugg+diHIiZdnoJi9=@YfN?8?^2X7 z=H8ze1z|wCaB0m#t{w&)UaHL?-YK`)w9jn@#JYcgIRf7@9Vvu%Lp!OXf=Vo6%Prrx zn7fS|CA?HqpO(qL&%jlazBn7cYnu|x!JuP7WXm1f(6vrZmMc&k(@eBrVv+%##`uR9 zTkV#2^l9UX&qM+7l&|Ta=%9qf(9Jn{jl6 zLU}$0tS44c>#u2hfb@_LHGUi1tT{&=5UW5pb6BW|1@aIw7#5gieAhC^1x-I~32446 zN<^(Gl;jowz91GwNxA^zS?XkAtviQXn;L8!sBEKJ*O5>x2Id^+A+K=AWNvZaiDz~; zdzh#l8y?Z?w;Zl`2U1AvXbA%oe==bL`WV8sU2wm&f%9X*6%>A@N2-F5BHX9Rg3MHeQiToU_IB1i{BF zC`?2j@s%tCXjg6-Ae7WW_+fmyeoqxk=D&HcckCU)SK8~A!)y)JqJe4E3bKbU;g2VQ?{@64yj*&ICE9Ac?Fz; zX6u$j*1(~}7wNLh*vi9DY3oD?GSLClDmgzK4*Aixv2Z|L&MSK;=%2JDN?wqB-OwBI ztv4&3Gtg+u6TdL;<0O8xAIo4PIu$QWkv(B6g}P`xnr9avga~IEkZ9lo3ODW^u^z<+ z_h^@HU`)iFCM@9z*)|V z`e)pqgTHJ3Lb5>STt(@>J^Wvji_QgL@8`>(k`W!BB#8h=GPb`msjBh>Q1Uklb?$Zs z9@;wOPdeT1`uXWkWp1(Uf#30#Qsx#p=(6l;m~IlI^vdq7liOj?mLV4z8pRP4Hg9rR58CKV0}lG}AV zQtmx>Xq>_JL#mN)9Ojsb5QFQmVQQ2ua+xsP1ryCsb)0+h02DSOcQ&E8fl=`w3)D=d zq4px^Q5}~FbA>jiW3vZnInMxK)8uZRDG%gs7P%`U$>269ev*P^kh1ZkATlmLhWSz0 zpVK{JAwTx9Xl|asUV$FIUa6F?8S2gA-ITAFuNmrRJ&0?>dr?e zCv%t&k1v5L5Q&_F7gT54!O*vgSU@b*hkla5swEaa(~wUvq4Y2zmE zttFDfmN87@3xT_W^hSg#V!TjEWRvE7Lvm8uYlf5;f}^{0RaDoLe#<(ZUs(#9xm~6? zL+nvK$vX{kPOav>Fl+DHsvCMp!gY?cGTSR;0&Rnprg9RA}jf;<$ z#hF_^-cUxW#X19h?96+A>sPq93!W{?{m zEVf(i^&n)Tn3YI1Sk#sjtb84IrE&*4c!!yF+{xq!W4fWw@Pa0&Sa!fn5GF#hOgB`C z@J%a{#?ra*LQGyFG<-1XUJZX5i>@Hu58E3na$ahs(|wa2Uc}xV#4vW=rom#m&RZY_ z$4LAFP6WmL5X2O4eCLXwXk#kgF!)w|** z4^FNfkp*3e=AdX_8#YVr%zLET1Q87RC*-3gQN4Wp#8pX7MQ3X)b7$&cCo6RUjcRxU z0y}`3Lh~Ikjb$5s!5Vlp5L?)i+kfWRyAMW}i6Hh0J1dsvNo-EDwM4kh7n?ejI!cP# zNFHyf*yuy&Cq(kFe;CXy)S;nm+T;QxR_XQRQJ?%SEpm!&KB=pZY3f?v48LRnemD`~ zi`H1b!Hb6IZuuxUb0?QdXT^*VUC?XC4VRZEf2xM3TVleCbDUU{Ad`RCG8)^UN^^A% zIU3aDESq-GrT0v6XPl=Jvm%tjZ5ikxf9fTBzl(-BdGH*wp4Gc6Y(c=GxnL{T7hmAq zVQEm3-Jil_gZN~NZ1#j_Ut~vgfoLF7h|Thk$twaxQENMf9;FTi5aCS-J@~-d+wG8N z_x%ngQtI8#j^@=N&Duq*wmSB)T9Lgvzcnr4-wkoSg@5Ms0x!_BQjI~WtQ_uRpszVY zg7rQu@@t)F`bd~})wXQ$kyE+88sCus});gdFhDp;!xSX8UZvU$SA5 zdbT9ctW_*?uA6mtitu)mEM6u=cs0(Fp@dFzdv;onp#uam$=z@W}*&ebsn})c{9Gz!xJO8WE7Ol*x@%4JV@{^u_ln#^_tJGWL*S- zl;<37;PV~XWcSDF3byI?X1HwprZ8KeQs)Lz?Q0*9Wa=(wETj!ic#3Ue2RBQooekkj z>=9>}ff5=7Z#Fh=!!p7oG6SbyR>iC1<)I6n(og|hVd&Cs#jd?V$4Hr=NH$~8>lm+z z(K80^k8QD)N0v)Psr5EF<00BIC)ksm2I0AQm-|V7u9&|Lazh2eL@fg>0>L{JwqY9(#kK9v`9!GyTmrMe~q^8mim;H+;VOMXHB_hE*m3- zU6BmXR!q&j^i;1?su0QXK6oLY+|jCM(>>CuSn3GqbYU|NB@2lz22iqW0t`?4&Uea$ z`FG6PA=uRC?8ruECEerKV`gg-orM$mU~m=)h(va+T;6xwG38X{Gc5^wr}P0L++^&i z*E=o(S>dHJ5rjQ%rNcM@(V|m$u+P#OCzB7~6pO-%!fXr$RAwqW7bNdP;Sjo@^*dnB z>HN$9nyjX#Zd5X>2bFLLFlc#YjTbXQw|2L;$={PO9SM$0JRt6%+(~p)eyCU*HH8D! z4R+ADLC#t2)CK5Z9Mxf5uIJLcKkF0t+>qZ~79c!W$<>hTytE)esu|;Mc4v!l`Hh>F zEHOAkQfxcB2baWLyb9nyX%;z-@P`&$Sqf@FS?HpW-|sfF`U)fQXfMCFu%nVJ50f`+wDceW%%W(L!^WEvX-i+ zwE98++EE~HI^Lxjw;Fp#zDWJ-{d@gN=EPdrSGDSN8jHmEK$J9gpiIlj>G0)* zVnzK3$74@NXLP}gluPLC({@H6*8>T`QzXhE*&?W2OA;Q(vb~Tlk8K1ucQ^JdDR^dP zyJUNojnH_EP-?aobm0ulXBU0OUl+Gee#_QO=!mK5THrYsVvQNY86N7TAOLs!` zStnh%O1D)JN8zWiw{dz8KXl8HoG!{aIvC=`IPALT<3_VJFFwWXMP-)mB1Q$fTzkD0 z>~b8MG}|H7o^5V7Z!-|Nt8P1jEznbr&s#7Q`+_!gV_4 zT6|2%!PXS4dkP;L=u)PgL~aNtcEvNpG?+V(K-rJ;Ph%zBUQe-#~t#;}N6cYE9 z#{;<;v`FGJKlFn!kt9FJStN^C)lrWxjSE$BG3RL%_UZmBYB-(6@WXe+{}k|FfS076Xl^ZYrYN^pJ!_caio`a~78l$GkkAp2$*+pY*l{My zxw#v)+Dp~$|3}^XfY(`6`Q!J^&CM-PphAHH1umt)Elt~`P1{sZnl^0{nx^l)xk*zf zrfHHk*``fM(vm`vs#U921*zJVN~>0_QWe*(R;^22E25%wl@-2NgWEZ$DHG21m?49Zv0ll+{B3p8Brbr*K;K+vQiUlXi$}1I*Sx(Pklb=VM%5$qx zhJXQ8Wg!rVSr;1Y#tILQiCN{FrZ1nvypcwP%@;%F&-F z7NZh4ap;2MWW%l-nVlbhLm4HJ5q%!}0$FjvdNHGACK$yD_)hI|i~=}8E*c?pXULr>6E*On z)<|+)6`$9DH?5`qB@VjCLBU4kkdggS5l`$&gK88cx_`)WMsI3YyDYDZSPEk2rkf%= zuF=z;!|rX96N1kF0ynU5E6*aisTn>+T838_gBjvQ4Q}sRwlATey=xfi2s1a_2wE@+ z+I6*v=JSjx5sU|?$ zD-VCj7I6GkG`Vo*Eob7LQ z7s^GrvAn&vrybH2qVYg5$p7}i4dATsQBy*h>}5*EPnhmNmO@x*ux3N{PS!S!OfH3Z zwRTw9-YJ<%Rsa$2oszj6-)ICaKxWeJQo=Kc&lEvUqEU+6~y7 z8)j!M^}XowGvP0_0oPh--cbdwuLR&9!HIXQWQu7t1z|PZ4%LtYGj=& ztrq#2$h5csAgU0G-U&!^YB?a9Pp#L8O4AX9qWaVj{{N}_R5cDUrmEN!a@i7bRctyX zvj#G*>$!Cb74~#e)%BDXq*OL{iHv}@S`&@Dp+@LS!FkF;s}+ZqnUY+r#-2xqATQL-y}OKEaO4X@u9#|Sz8=*Z zg=pJZR1sdP3hvY3`Fc#kS#jJOJ`&*wRGC|pBj6gr0Hmq2?d5CAdEa#}PS=UeLv8_={mA zZF?wmzt6%Vuld zkZr-e6Gos0V}?;-iD<6D0z(@m#%1%S`{q%OJ17zn0WXBVwdRkumg?`cC4okH4({0NJbeI7*McdXd@85 z$~RC2C7k471XWN#;8^cw;f@mfawjAl+0n!WE|fxRZsf6qrYx2Nusl%CvgjHFSEI)i zbu-K2z=hZ~1w)Tf%3lO?BZi?S=-_Ncg@EV)dmB{4q7G>!3i0C_@K9shP`0t0I$x(` z%-(WbP+zDZ;?W2rYc9o$$)cqWtcHZa$kZ>vxk(XwcEU?><^G)SDF3Q!Oqp!e%z0Jw z=FFWrZ+5dzyCGo)O%OGhEAXxyv~Mz|>;cGvWr`8t==4M+&Qofe=As+2Atv@x3*Qqa}eklnDjCs>ggF(C_WS^g-eZ!ln)79pxKrp@F}Z)$5M(%m!7V z*1%(Z*uyc}*>VlpN#bwP6zJc)qdIL-E$Y|bEF**Eh{(}wo&P{&4OhY0v(c^r%Djnve$lKc zvkWmQnkkw&maMLyY*PkHFC!Bh-;}>tZh^z;n zbbevid7T^{mXU{18O(_%`#tB3J7eK~b*8I#u&bD;=!lj*F2z$;oR*;6n)EFH$%b*} zCI)!7t&2_@Y?d-Fndpo309ec7OaSY=x*;2RN7svUpuD1i8zC}bB;U_ok!uECNCRDc zv6RM12-b*>-Pcr`tLk-MB@7%0do2~cs(SZT!kGEmVa&pnWn45GHL*+!6!v18M^2=$ zd^wi@sfS&~ibbKHS)Yw=BcrKGlPVs#+UjsoWzy;&;<@1d(|Ef8f8rL0%3 zs<@IgUZ!xN^m}@D4*3{%A0kWdY;k(-xq)*B+r*oFb-fKO#)!YWk=9HV?Yt3T$QqYl z`S$Zu>7@Q=8d2ShH!}GR$$o+d6j6{$8Dt`<&95}Ec3x{Eerq{zmWhqrrzYF5xYPm? zk+Kb|)@Y|1=|e_WVKXX$u8!6&To`6#os>3w*sb_;Wy%QUhLF&S*fGDvLLqi9!Q7bz z(>j!Ut?(x&yFpi%vt^Dtw?>MrQFin7{$7=!XKAa5go=YmrHdlCmVxm_Hfga+B||3# zswjWTg-28>bh3C`n60d?s+u#ms;Xk{thqQoKD%;Gb6_Kc zF4jS|2K-ph+AaP#&mgZNr^BX=(~V8_L{IlL2wSg{VI|ND7m&|Yv&>X5ewIqIHjaXS zqtgf(1fMEmCE`_iWp-K@V@CpW&iaKbGqYw#t6*fzM$bBm#>G(y@I{Px%{VH`>Vr*o z%xE}^aph`uClDDoqG249k`tkJa8r^H`$CO;&}axTLNd}AIIPNByV?~;N;0WiNkW8B za~^FLB9E*ftP3#=vY;&{kVQFDFye9`3+KTy(U+6w&1hiNVZ4r3d~f^rnmzO1Dz>=lz@{5h3zoM?E4^g#0L;B1YwnggueY z_GW6jlnqSY0f$3BavQ5M*7Ky5VoL_A2ia+mki{V~Xy>k3nTZ_YrB?5VGy?b;BVoeb zSY=|^uw>x~hiMj3st?y(LkI>r1`5LIRFe7VpUz}`!tL~#YP#guyQ8GL+4K>4g9&w?3-lSv?VLKW!z?475YY ziRhw9A{r}B7n*)R?uFaf)jv-}1NwTH3x-~c94mpA&LG8K^Iv46LqXE5AjFx&dF&SgancrF$_vDr{Z z#ayKNK&;Sy-6FH>-b5QKG6Y}k83L$2z*!emNQ{)$;$msG+Q}P5Hi2STpOt9Ka=29v z;-S-^3S;V$GTj@NXYzV0Ggjs>h)3QThHHjsL$XhuShTnXgGxpu*X07uXg@3pF}-3* zEOgisEnKexvqpLSq#00ZI-_tsRHCZvzU+|6Zc9Xt16_*@D~qTGTUSk#zjddr809z$ zpR`PE2R8G)F4NIBapuh8<+o^s+7V9g5atG}F+5*yIUD~fu8}-yL;oAkwYEHB0L^I? zudO;w^a@$Dj_SOM{TP zbIS7QjDBfr#`<#$npyS4bxY@u()&;kxu#2(OzeV&u4Bky7)-(%!9&Qo8Jr=7RvfU_ zawK3-nCy=3-cBB#5jUhn$R?V%do;9ax zu8Iyv_AM7+E*=wPLPL`^LqMtHtX3k+$dwI|8};Xs+cNW}&x`*S&8n`dtxceFmYWEw zD9lYoGDS)3@6+=^bh63u!v7%0|Gy%HOB%ZuR2;<7up!g$zYD^Y1P}C$!g#s`IeyZ-&qhNS|fRERYf)=TJ1|pHqka;^b8cy`` z1!LFbLcCEcZoX@s%v?pJoU_(QhU!d2&k6dQDYZ$Cz{>Z`4j<+{;0DmWNb4;|iYh_O zW+1*oRf2OFqsSnw+Xt?tag0VvOdwvkS~%B}x*+4Q4!99oOtPXc4f{tUS#Lvu{4z9T z2S%<9Hu)_+9#BI=8yC=Use5WhZz0fo3EHs7FG_Q-@b7Q-E8wE6 zNGY(vgYI=8K4nRx0ZLaRMpB(LU0!^pSVy$Ty7Rj477R^rmjW|&o@MH||Oxqvd>#@lm$VJ)q zE(P@2Ycsqo!Ca$YWKALE2nTa>g5I8BHc9N3jjBr%-iK>2kh&B7deR4TwSe;&?}y8C&jEE(6Bw9cQ7qBce0zQ8q>>H|9l|V{eE8vQMVmQWHeY ztY%4L*IuZ8*&>V`%F9tCkuM0#)Lol!J=krMk9A41Omfx|ODddoM=xIHo-hv`;zSy* z2f{i97IK_~x1W@tkK`K2%uT(StXqEKY8`?G2b!M($DzJWr~z07!n8nde~!K|nzA8Z zzkD&-2E220MA}^~HDWDb8APj&8E4szdjW37t`?Q0fy%Zcdf7BI72yMoy%G$S5_=nR zP6dZUu$ZA@1ZHNjxqUdk#%2dFQHo}Zh==m3?4dkebfWCWGER`R#3=NO6)5U_!tL3R zMOIDWQf4#TnvIyW*mUtEcEfJ0E?}KpZoQ194P9LD=iYFxZr7AZv0538bQa~7K($t>ry z!PGZGk`@a%v$0SWVl{__lYtsmEKKE>LkuI~Ti)EnMO197qYJ5BiP=-Vo_sfUrWT_Cr)rVI>6FUW zf*S2eei4pb4~{df>BG%(?Ua|WCxIzxf>$~6%iS|J@&fC|qMAlBD5KoeY#Do8#16Jx zG&r+{iV6a30*Hte=K@l1i?Ik&m`{0xHTC&yU441O@+p~y<>i^WdT=BiT;0OiOI>)3 zolFJ?Ap(SC($E|W(z~NesMIW%7w#1p-obn^Gm4cT=8lo1Jjhj6*mwHrVublsO}Xl zPxW`c8OxNTdO`8SOU#34?^F-B>HfDpDuWB5@qM-~|Iw?hexqsAum=kQNPI$nVJt*( zz(#GxhFW2E$}wD^l4HS+L$*7Z=2$$=rz4qZ7C)q~l4S^PjMYPNiqXG|I<&b5H!4CR zlr@^Oe3=b$N)$g#&wE+qACe6+0OX!k2p-&=ZT&Zfw&? z5@cB~#E~mWrj;?#N-OKiSl2K;RMCw`vEkkh-4hDyjed(jtBJMpwk%SLWAl|7wzfBUaUV|wmv!hI}LY|UO{7H zoG(cDA}D%l!jL^%HwL*u!@hIUrBtEJeuav_TKsk_U)b4mVgem=7-jl4V-~w<7m;rWx6+yr5Le*3Ly8jnH^%z8eo8nX)tYY(vDDWtu3to^5*;L_ z1kyG%hvv;OE1NCL?6M|$Qv_tITd~wabW;QiGCW*}13`K(C~I0~9@JRiG;Zt6+4vGi zm~N<>X%zVr9*V{C6?R@IQpq`~zw<|>^&uq*LCt2cP~?H#8{#9!fXF4+WLEo~t& z#Z91cTYcD!>Fda%yWuRJCmu{6Ic0;o=%!)x#u<>3#i!m^cM@8<9WzJD2oE)i;$Emz zvdSvVdJ6^$zmXJqVcCji9eal;Hj$(($Sc`Ss=IG+2t8Dhlr}0f^g5yUx3bzIDTC139F6-s=W2B*?Xd*iJ;1tj((Wwo!$1BA0oqpwLOF%vIj6L1ixT zehn&>7m|frq`>buv%ax5Q!gK{^tDPA8XQL0q!??0&QNtKh;TYvhdFAd+r>^JD9;3{ ze0lAP9XQ!tbX3a{tt%vz}D2Lk{;famPU2Y?G$ z+c&@(fwM6g463wT1D1g|RZ=l0J+SC329=<*jk9$4oH`ZM?Do83ObMCFF?%>zbC9-! zyJVOdiqSrsTXAPZZ8KI;X4;Duv8u)H$IGq9Zx@VjF^zgfoa``R8EI5U_JTYgi+zMj zs)o@lE)ulH2`q4>Go1u&>L>S-P6-Eb<;DQU75u_>o#@u40NIT zT#;EZJ+lyc4cOBlOGMg!)~HvjMX^2_l*U#mwE`JiUBHP8E6I#|VO;}OSUED8DLYmM z7UXN7JKyXRVa!DOgkeUFrwB05XJKUsm)nV4Q{-?IuY_!%2B7#|<}tLec5>ItB<2fk zljKkd^@&5PHNI4>Btcw{l?HUcH`&h6L>2EXAX&0y4Zp9;B zmy)8zEUL{lWAYBEe!DrgJ3UfZXcT9B5sOS%?oxSj!(Ks}Y~x_N zTk6p@MRF0N$i<0HFWcbc+(BK<>`KTYiJ&6Ya7j2OloWcTrhJAo zN0yO_1Y+RiQh;Pc9A*0(Fovqk%!zKuu^=O>dD89^bFNkdPKj#>v$o*OIHbO0x?C?g z4z4viVz4@Z_qMF!?20*Ne50Dx4hod;&@9F|qdG{?6kgagpi2W-tj09XGz3kFS$~#x zz_u5i7noT(M1`0c#e!0!;1I#ZH7$@k0Ye76(cL-XToYzMcIg2XnJdajhpopNEs>}M z8MaJBlnsR*<(}~!E}`gfJH2x5?5cTHvu0OR&zw24dhYBljK9=mPQUg{x0z7smB^e{ z$?%RHG2zj4h+l-Y8w?@zhk9?8T<6W4IcwJ3nH96EhUtl3%p?P0a|VCyi`vWSGWoE1J>rjxiY$5l|<_ zCChmYTnt7>14UL~+RO~A;OAF`P`Em_e*-66O%4Ow~ zpa;n|FmudLcBQzLdJ?=;aWHOCMVL~{i*PmxB1*_^633e{XkhygqHbUuAc`vTl1Ow9 zHTz)7lQAlLXLS)vdru|0YzUN;z+j4S?dS zDU0}5p7uBEO_^!jaY4tzR&8$1l6K66udUtw3aq-3n#)2IE3k!NMyE(0nh}-fh7U!D zDMEqDQv3S}CFkvJg@^{UdP(#lrL-8=+CowiESGR**gVcJh2SLmE;$7zWE`_aECO<1 zDjxxhlvqrmOPoE!$n5R}b_^5r89~_z&cr~(2338aj6!bOebP@_VoQ>E;)71}^1R@qf`m z%o8{hP#ZEeLX1twyt_{#vZ0NOb(}=5Sm2F$dV04Y z?G6pmDn-Jttjlqgs|gJ;BD5s+(st~PD~p+3!|QT-$R@c6*^YUNQLyM=p#u<-ZfG#r zlVL{>PNq#3XYBRA#Y;OG<6vv6>W{Y@4pwQO9n&0-fUSv|R&LPY8>6UXSNTutBvpbc z*##{LK%-i=1Y1)~jIj%w7vf-bwJ`C_W4Va|9lJZTMYSMDH2-)7q8x-8cR#a4>BDsBFD=M{U-kjRS zGAeNk3KJzv+N2l7ehwI3%e_NazkQc2dc)oPcg~tn&!Y$yK*gi8B62+F%>6%AkIVH! zbnp$LSC4vRz=UEMf&(4*r3}Ws!!_H(CWQR0SpZ>AIq6Ub)jW)uyJ^R$yEhz)p4g@r z+=qh^2JIgzBs;LpG%(PG$Y4)pU}!`8FmL)K6H&}N#8?J9pTdHrUBuzGk8JT(Fe$u+ zgF+PC!{U{%i1MrMv^7xp!fsB8w#~@SeJ1Or=BVPY37x83EJA5~coMF&&WVLp$GW{` zSeV30lME`d^cL+CV>+C*yNmUUQ9aJ+?nDk+l^G0Ia@b%cGpofID6lz;Ra!_Bh)_xe zC&=u~FxMBB3B8%I5?iQ80|JUrg%sm0(Wps6dEpW$D5e5KK<#vHZ5rc=sHVjvN4YgF z6x)Rc$hCreeHXemHy8t9bVRE>yb%cEA|J{QG1IY*GXvfljeZ5oD>#fJ9mnD(4D4tj zC*gQ?o37Z3IxuQn;ju-}!F-@1kNYJ9*P-`dUtfJ^e@T7{f=!^G6?FLY# zAct3U<}PdFAoiPZ&_Pv&Wxi~6JnrEZrS*l#W7Fok-%u zCOF6-hAZ0g!aTbkq!{T_;un=L8lW3xhI2G%Mtyd(8ZHmvlm;}1)p9SLGYLq-flouN zK)Xe!4P8!X!sae>hmn>jtTXflL9$VLki1y&3G|3i&H!ZMN6=VTE>1 zW!0?O24QLnjhJ^=NXMuhY_T+>>~Sq#R8wfimfgaJ>ybW;BXTV+?}3lqo+MbV(&9dB zbA=KWE1Sb%+Sl05M~fUPP#hP9Y{O(GF3l1>C(wX>s8%WgHPbA+GEpHt9?t%-ljE4g z(FL3jUZ{*%b%m-L2wpo>z)AzJ9^xty<^fnbt3~(8%MUZM7&X}2zS&)`X>Mv19NWDS zokzkBre5JB?iey6d zKgr-7k+G1W5n*yG4O0!_D>8_gztBVGqr8E_$!zL+f;k{68Efq9F~g-xaC$&xRYXmZ zNUhMu$TsI88-ZmoZfxQ?I0zNk5X#_ij;~sto0(Tw&fRXA9;i^6B)?+V?#By%B10I? znn~B-GZP=ey0KkbGAq(5@4?lb;yX5^%}XQ2(vBW$1IMG+KFT&lhP%fQkl2JsdO7&0 z=n@X@<(F|u8IvGHvJm$_Y6>jA*fo|&1CV7c+=5Zx*n)#Aa%@L-PPO0nGMd=Mf)p=1^|c#t z|81KpF&HVXY3LxkDVv~5T%Kt!&)}#(c*GVi@L*xR8RD~9(IIFKyVg(_ty!Qpc3qQk zyE}-gTvZM2lOr_$6J<32qY^KWH7T>ZhpV}{YoLKk%f@+NgFs;v-AObT5+`%(a9*&f zuGtK0xc>-)9jXL)Timop#Xxd0)2=H>mj_J*e!!N-8N;we)#Lasri!9&N!b`X?#O+Z zoZI@1zM>oOuE<1J2;`bLb7)qtEy>7{JGG3o|%9P_` zPuYtTDUoxc7#6s0LUxc)29cY1L1cVO!`}AGDGHhZMjaz;X6Jq~c^S<`x@Lc&oY;`9 z-~hnXycPrCHe^MU45f#%9p+SyK<>oT(ndy~OtCEa@Jzm&aK-xo!|AbiUsSW8-f%o- z2T=s#BI4*A=pd++nLAI#qy6P6MSO;oH|le9C_2-cc!!E@;kBqt`R0WMEZ^V|WnNkx zMoP2Ts@oK!(pXM`ogBuj6*zDQz{(y|Scf>u0e<%4ILMDY5Fz!(ntWcaljJ%xdqy(X zl{+*Y@d|>sRHlEw25bD zJ7CyAGvhpGo#Y?oMqe^EMvtm-Hlj*gD7=;n8Kze1TM~O|Fe7t@HWh$d3ca@-5z^!Q2rB=Ff;>M-eV?UC41$FqAj1uUfV&Ggqd`lv+l50N}&SR51iJ z*4E_RqzFyI9=S5>LM}MgVu?(%^dNR%b8iUL6p2nA!+NYQ+vaWWf2A*XGk9d%(o7W4 zBr$=(c@3P&Mfv$#tr7Um?E@P*cxR<+j1AKqXXuPm>d0Urki`R4(o8wK%Z7F2tq-x} zj&4cSYjA!MsYWV$z#_J@MALtPopG{P^JMUlvWX8KL`nYWmaPt4I$MZg5?oP%R7Euf z7<5;Mb7~@`1z@*M8I7)X(KIJa2kjgNxZGn8MvWkD>6p*xI57 z3&_mH)?^l%UDPZErD85t@dI7{w$++0WVp(Nxvep5ej!4!ql@;+ z4$-BFsCp2vQX`d!6)9J-BwDTVvdPBkwvZB=i&}XDS7tUg^SCsQg*)9mpEpnD8Vi@B z>*3TTl4c%_2M;OxQL;iW!j9~IAoR%DkO&pef&7cycqyD)#jw$GE0bAGysC3Rv&Nba z^n=!86&|;8^>mCpM}+EAFY2V7j*Mws0~6jyS2{D%m*OgfTX+7yU-P5(pynpC(3;6Q z+f|vFID9Cz-HKjR&uIf|B@`#t`Plp6 zg{y_U_Jkb=jCjH2N03t$-05lS@(qtDk%xsjQ82VyF(z$04QhwQ?&1mCU0ZyeeuX-k45a_Qu*fg!=FERzKvZB?_ zy;UNfGVyw(-f)aDHM|&F=i;IsQ@^FMhKDsVbCLCC)mARHqKkOS1d7CpAP|Jh_HSy{&`j1F#=x8B)jvliyTq@f2 zaw?a=s$X@pG`YnTrJ1HIj)^6vg3(Kh+4M$r!M8T9y7%C}a|F=t1u+{sBcjAHxHhDI~Tu@K})?4&5hBUR28aa5=C z(mSG$L*1x?OP>5MsyWuID`gDEeS-t&*y5wGnZgzA_WQ*wn|);Sa43eEgJa3Y66wtC zVPVn9BRme~T2kOHHL_#IBq3gyeB&UOtW`BNpdjSTgV)f{og!me_}%at?6fL373$ERI?piR97%8A_uKW9a;<4Kj%aSzqZdDT^O zpt`K8x^ix1*R-nHi?wMFZd&s<>v5mjT=vE)k zOkjz}of|fGPn5)pYD_>8>48)w7(jRTEhz_~$A_?F*2Zj<<6RwFxLFrPtO|L^B49Ng4lWJD5Pz7fO0fTo#g3G>mh>_L! z#1M2iqL)Zu>O=^YHiMiI>4!A&q}fOslV+v>Uy8iBw43BbeY?17U?4?i>-vk%P0YvC zE2#C``Wg+`rNI%{Ed>{%DSVspE-=X_iLabwH#Qfz%VC#74LMc?Y?(oUk*(+`y#f5U z2%S`RlPzLL@TR`nEI^vH;`riXRD5xvRYYnnjuORct!Z8u%e#4Q#Ma?9tBIds;dm1? z=O;F{Z|ocF?ds}xDUw=u3m1Xu&*izxB8i*LI9~&cFed)`74-X&oX{YB%EYHnnhQuG zVjEyAJ6xo+JfU?-6e>BiiIpY^@im2n+8M2!u9`?GyP~zF0fbgx)0FrIH>s1d8ENVe zQ+7+=Ms1YZ1JH+TRGAq0zQH8U)$nNAT^>P=)Ou~~HrLqeL`tb1b1d@>`vvWVd@}nvs z4D#OgjxNb9MsSFS1L+&Gp+k)JkVE0T>2fMkfDV7!z@Xs5+ID1kG-k;4uAa?Z_!5)M zVENh^qtTIMXb_s(+2}BRmOEHYFoWxR`XxHhO4()np(Bfa1U(9uKL$0)bdj9983K6t zl+8fdk4^OS!81}T6oBZ+H4mhau&pfg9T4;w!bRt}=G^)3FlQJNxHY&3ca;tBDC*30 zxVE!jKfJN)W_LNdCqm>pkS&8ABjv6B`quniPv@|Al9FXikSC%(%{u`jel~G?NFoJ{ z|DL$X?R1imK8%PWF(#Cl#>?`WOUv5GJA&~EwQ_PoiKzPzxKxwGXBn%eQ3H{XbV?j7 zOG}wt#K#CrXw(OxeRAW_TAwn>4;zO245B6BsV9p@;aMvLmv1i0S-XrVv4_GsRZn5l z!u<#5Sw5=XHN$KJ+=$LQfvQHiLfri(HXP(`N4g?)8 z-_WyRplt&##p;noVp1Rn+j{yH*@3o!MO{Q9;sVOH4PE5>2D?$ujY|a6+t#-c3T+eA z8H4=<&S1=^IVXiU1lOYx5gq`9LxNx9otK6PeIIJV$>Y`Yuac;a!Uht*}=MoT+_CV4D`WkRY9<< zK%>=_IV|f@DoZ@xLqol&v*wh%ix39AA>J>nQDpJpbCFtR(x?ewHm_@=~jKvtKMwUYv zq0EHQOK40H6}ob)NHDTw9OUNCggY((O&=25h|*@)Q_H}MCOp{IkH|69?l!dLb>8SV0mcyu1?kUOqVanVEi)F0+7NI-&T zrckE`T>9Mk2H9!A1vAhaOd%;Nqn6+>$yhV@aZ5NN1(9?Nl0D1}8`sXBK^NUYn=qtt z4sN~e!$sN7lJ*Wsm+mn~?6rbSsh%2L7-!syU;LveKY8qQD*-4qj2 z&V;Pl!t|T8iFy{+O-4;VX5*zC5VD=rQj924WuYW?5{Mt#;mF2KC;6U^`r1(VeIa*? zm)swK?!;EyIbb(q2En#5qey7-O#JZCz7b<G*p{H<`JW@1E6v5{e)he5jv zX)~l9f^CNTgTiNs0dd>fDV9aPBmNuvoc0+>9rT2NNrQH9hG?n)tE5EM1Z?uoW@URv zM;FF7()YHn8yry{zRlXMk~K%LCP0>(iz*#8J1jY=gq$}H6?YtLyzJZDcTIHkkW7uV zbCfbK-|YgE+5@&~cqq}$;)v$CsXgX1CSFo6jJ*?ct%1HRXysTEYZnEf+!(f(BPm){ zh~oG<3y<3)kYzUg3^S19yv-ilDh$*lNQ{I@R^12EVX*VI+?&mF+hw5{$=M_=JLx4% zdk7)te=JuYUwVkLc zM)?J7#Y&5!-qsHEZLsg?HeH|T;Ouwt?Lpv>jz3NA?;6ZM_`@r zl|Dd_E~9M|#iz+Ao1Q_i=7U@kliDh*w1$bsW~!}(%es!CngQ6TM*}hqS^_l%0>+0C zM6ZmX;(q2}1j6_;(6s?&CNWm4e1yCZ%EC<^IgBF!ewo4dq1MnYnTrLNj(!)m8FD2O zw&}_X{A=P_tew^`7zk8yK}3^c)(51Skk~Z@6C`WUP#at{pAa@HqI60mw{f%|cKxV9 zNb3S2qS7y+F#U{2dk^~;nJCDJE#GKM@Rx=O5+T7jn9{_bf^aV^@+0OF7!VL#Bh~_* z@|%oj76z^a>e?($c$C9bz@!tK5}E$QBo`>@mcYOp!7i~j6WpsBr~JC{9D*rH zRJd?z@&31l!@$mj!M6#XgNdg&155~0mMGj++I&|j?X57UChi%NNF06Tl~#9}k_uy&ndNBiJL>g7wAM zPpd1z(YPyLA5~X^r(oh4LrgLyffMWyYl{t>t}nv`i5!8tuCT6?L0qSP`<-7FoBOdQ zBH9G~Vl5DCg^9-kh{Svte20JpLBiE%yd@?JDo>!UE{=3gw{9uNmPoOmtSeRnY*QxX#JOj?a%VK2hhbU> zUnMOh&6s2pGV@Sf2wo)*OW~Y_xgY@!Au;i+`Aa8HIyI3wcRVdckzxLS9|oZk^q11w zOt2qD8w72UerkgB8_fjc%g_ZS?mW~+ODzoi5O6 z+4yMX7_DoBv_LQ)r0_*hE7k%*gJKD`DVAWTVhQ#sHX1$?$ueN_9zNY*vPYp0+>esh)NQONJq$tPVW zNS7fPewuKrQW7w8BSDf(5-g{<^8X;{)zUbx6%ecv<-pblLSpTikdH|Xf3d=1-SHz zYZC#(OeVGjEdz-_zzvOU4P+jbI3d;pX?!b^s=s7#iM7%Rv}W5gf93K>6_#zlA}n2_BOXxFAmE z^#vW239=Y85D>vsv4#X3;^HY{C{KyE9D#<=L||!sib$*Dex5)-(M(`zJzqo2QW!** z;102_AlL;Hj{|8r(t>*=P}=4wt&am~YlSvXpr6S3PZXlwe01vmM%q`6gAeSr)5g?( zN#Yw4JSf&?g6}Jq;31fJmeAWiA;=ME2u%c*)@KQ64+?FbKtECNpUBxyoXt8{IS~*1 zD~fo4`52y7=txDdN31Ob`(Wa+^RzinyCO>KW9Mn}p0+tk>r06o;;?);B+xh%EG?>% zt?Z1_7nG2Ij6ytyBv6)07)+&YiqiTRlJ+1B`a1%p%|&T_4Ed#R32jL5qF4(AFDaG) zaVd(9_m=bCn!UGN)SHi)_m=nGTIkJw!pH16U?ZG{MkjAGjPz&1AP))Vi?u+oP_YEH zF!5~k-g4esv-g&Zdh_w-SI5KPYXmGd^hE?siX~uASkxhgZh(ecVxkb_39b}tj$jCe zk@P7CB9Va!63`=RY4cIqCKoQ_zz<`-GEB(OqH{;O|99g^zjwhPl>|q{TEJ6&blnbv zPL1HGSl!gk`^|g5jydqIP2Saw+AO;uVLq6+)0FSSZ#Ufu;53N7`y3Xd+PBe3aIg-)a!> zi!49;Now4GHEemSCY`2|5)U4e414JV&6eu5kT#^8Ajvy29n_?HV$H zPVZc$qU(^j<_Of4Y?u7J-@NzhzDwfeFvwDZtzvZ{(={uoJb@B6S;Bbkh9Foav}~sG zV`z6PieMrb?Fb7_S2Cw)3j~M6S|B(ABTN@94=Fwx<}N|y2{cTXoc%!EC$1rZy1Mqo z*Q+HGA;FP&eCS#(s2o8-tObHqFcKeHdKGWuLtj;b$`c$BtBX%9UPD2J1nTPI!`JVq zE5U;>@rLRNa!~@`m($Cm8Un#%BSIj-Lqd=vumnB?Vtye6ApxgK@i=&bT$I3vKresN z5D1|M zxljl~f{8HkICz3wl)#5TFH|MxmQCVI5;8%66_O#9Dyb9ArSK|AqWYM zVd9K2m*5eYcyvg6L}+saO4}Tz_2JTY`V?ug1ifM{5DdY@!zJxgFc>KaEP)Sf47`k! z5JG}W#G12RH0f_wSAuOY@$fxCE=u6Tr6LJ$%hfQg6T335>a9|FC6K|>(8 zZ$t>5AQvU@A<)ZLGz5afBSP>5xhR1TfnM&{5D1Qr2*DHNq69t!dU;qwAUHlE1QHw* zf*gS*@F5WMQy~ZmPQb)-(i7yO1U>}ua+=idQh-je76`gw;(?L&Ir&cy^19`rdWc=GTD8?aypKVvyP`=N)nZO2`7tlGr?4`h6DweWMb3pduizu zeDi()21cLoD8D=K+zo?x5!@k^H(1Ibaf49d@rZL>>0RBLW)`j$FbIY~qwE?`HBfcx zN}wNEL9koC7ZRu+*R1&Z9d#wh2zOi{xJ;}eK?O{_An5Igc*_x}w^jm6>&qkqHoZ<} z1}y}=Fv-N`(!I27Q#`>=i$~Pu$5o(X>Q2CwppwM!IKpROBn(={NJLu*#={8ShA|QD z4KOSV!U7CBB!U%U4GH*pDMcF(kn9FdKUuk#@Hh<61V0vQNWhPZPy6*qZ^xO+3CW|7 zAS2OSL7-Xdx?N`3a&Zj_j*7KF!2KeWH9@wN)&jv)v4#YzgoSsNHU!~&)Q`;pqV~aX z!JI)JH+Dkx?YigfKq+aZkdDU(m~n)y^34{4Z7|5>+xOCLwXd;oqU z+7kE?iXt#Rgu7snL;`*r+YAJsQ0!3vejQkXonpP=AiyE9h6MVt8|=qGYtzne4@p!) zf_-9bCisM633SQdWx}hwlK2Ee!L1{RF`Yn0Wu>335>a z{|Qf!j}rJ#Fw7VA69mtLokH^?NGgv)FjlMuf(sQ(P@!0x!wiXgH(<&L=*r0YxRBsw z`Ba`jy}LetKKz8@JtWvC)@FkJiY0hZv5cO2cV)%b28mEeP%WcpfnbSPLxNDT1Z|2X z7*ecF2SX}INI3$!#?wK9Pzdq_>fNP-9N&I%4GEqSYcs(!iX|8;pKNCI)VoUuUvC%J zkYEQ)yvRL4E=u6D*%RcW1ir`_CfPQ0M+En|Ptf*=IuMXeK|fD$rC39PDwueT7@m5| zS#O$Q^f^v^<_N4$A64%&PoFQyx8FoSuM8x=m$vZ|NS;7r@}_7^e9HKRR-p|E9ujLa z!NZCrcvi6lFDRBEJ5~~FD*;0)h-;2OU0sJu*VW>hCs-%ekbs05?`TM?grJE)X>(Cp zzuw4jx5IGI*af)T*aNU=U!!RgN0)_x_I~xG7^uHg5;SwGYits*wCk>kL z8ATJkDAv|-NX`VwnJ@z|8HQmHYJ5VQOujb3;A;e{VdAxf1XV(iBd`R%GLWD_2=W9P zSS}ivFKE(+Lfb?@BCab(iG8l}Q$s==65Mw>W9bGnx^5NM9Kl^;4GEqTtIKf`ZWmOZ z;HX%ep9FYHtpv})#LJ)FG|(o3Uio?}!44SGHtnTtmpTyagGnZa`}fkK(RHi042}_F zF%W8a1%|K_27NbyhAt_%5IzWlQX^nu(BcW05PpMDGa@8NAaJ6`15T9h zg#=Y%ZJrOX3WgMf-GUAoN5%+26EH=juvLeU+eU~4!C{zq)d3+rp6&bzjXM?Ac1-n+Vv#Je_mS64NOdI<*KB^V>$EpXR@lO13QG&U~16M)(Y zW953`Pktmj00UnHkBHUzqU%9H(lb2H8sRyjTkaNoDN`D#ThKs8TG!e8omXdQ80M2&%<(1%VQ} zwDOZmnD>M&p3o)26E=CmW>4r6@uZ9Hs#1J!tb96TbTt;MY#bSr)#^&Xc?~-pfW3+( zcucVbClpKYq++8X^$RLTpsuds&j(6f^WN35NOWxwzfA<{x7CI`43x%Z)jn7c2w}+B zD4|OXLmpJuBLEMnmEbrGrrjMvLFEY4 z)kWRA=Dn-yE9m+x3^vXQ)bI5+T&^P*+#%-Zk%CT~5)pLHsrms9#s?JAl&ItU3tmAt4MI z8zppk!H{oPSAxT0z2P{(3B?jTqge0Vt=BQMj82~k8Z>rC5U9iY3^iSeq9N ziHiUj%n8)hmArS&dskN?bR8>xn+Vje%g1VI&Jr=1HWkE>q}w zK>RilsHK?w;~ zi?u+|2@~hoLSR~9(h%P{?UffU*vpp=7%&aCBGA{Zf(i-l5UXo4eBH0E1c%j?;0R3o zYX^Y24~AbmH8JMWy?psPOyq0y^{}8qf>K#Xa9{JTIq&N7-@E4N`iunAOu%52iLj|6 z?ej2Xa0&H8E))5BwtPDzs1>V=hIh@;H7l;o1SI5#JR3&ZDj0r`#^@x0?F4oP4+0`<0%z|#7HCM`eC{SLyhph_lgzI`t( z<6*du0dSsJLjndQBp{dHaXjf4Ng~kixg6y;Z&%+0Srm0-#!uHVoUzLjrmh5}QHvw?o`- zAo#FYLjneZJ=+QJk(CsM1ezy~Gh_nIG>SmyJ_UliVNkpT&xo}^@LR<1tRVrpKVS*gE0%yVW55!CQz$CH=MeQ5VGv&e z65wRmes@fDETTJ3V@_b)4?6cp;3+cOHSPzTdpW*ZD-j5{0o0mySU@9^&AU|~5UfQZ)P!S2{ z!f+9lkkdycqOBVSL`IB`|4TEe*QM3jeNy)VH*80m6pc|>|I$CZ$D z4@{7_{yBh`#TpVE5JJaAkTBAtGAQ(B&jS1px>4I;?bn$m235c}X(w!z?}r4vVs%|U z8~)ia=qw3ViM3$EB#dx*IySrXPKIka4Ez$%6&>x4+hLbqHJ-IFa3?VCJDodOgw^U! zprJdyVHl{b>Pn!lE(>=8b%(kVsH;oWKA=9Kt_14pQbpGWuoBE2!U7E9NH8SU6$HaD zq&Nn6T+kr_MP$Ge5s)2$KLY)Nt3Z6Mk`Xr~;INDWCg_DxeuK6_aR>u2-MYO+I*nu#5E*PR~M~qK)p>}3DngsKJfJh`B+G>3MS4O5!0ar z1f3%Yh`Ch>2)Ondi8%+no$5-UuC6le18Tpz5`0>$ZlRpSe^6I~ZK&S}nShEtPzVIt z_FPWM;IFPoNMe;(-6UZwUdO8|f%t^|*X z)y3)%UJt9QEmBhaK~V(brG+{V>`MNmuGRx7rV3R^aE*E(xK^#W^MK%lfP??``_x)K}~ zt4r)2yzWz10(EtDgs%^)E5Qk|76_hDEWuMS@d$Bc^f4tMAW<@LQ@2YeeY~XZ1Y?Au zD-fKfydA+fn0T-+gSJ!&2uKtQmOidjcY-Rh76|4lmf#wgc(7SuxT=XNQSo#>9 zLGDmr1l=(4U<<&kQUU@J#e$`e+tr<5mskq~A66{E9+-HrJAk=E2?&(dHCxhuNnHsZ z6l;Ot`-&wv4igXb2r$Q#fIw+oprn6VT?t+kYk?rC0~x_sn0TPif#7+e4GEOiRZG%e zrrrta#OkW$WV~k8m4HV;l8Js_gGe4Z)KE1>x+j8#VhsrjinWcnAAW{mP|gJE>N=6_ zK}QY^tvvufm}S{}f z*H(2U*ecc)1b2(oRsT-B_6jN_P*>NZ?Ez}Px)Nv<+(-BtS%59#kY9xB%j(z0nG|!C zcOuJb;0{xb&eXD^Y*9%vIPl#1SD4tR*!EY67Lwp&prTRqz{kZF=DuAk1R|5T> z%T~VLrLF|Z&=v^pRV=|Fn0O`I1I#`pAW&LYlBEB>x)PiaYk}Zt#S%OR6A$zeU>;Kf z0;P3Qc$qAFC_Di*eUS@cO8_+Nwc{ z^ORF0;Epra1qiqj7>`&61X-meP+C_p=L1Fl8hJsWu5RcGfofG(0(EV*vFHS9NL>l` ziq$2VuJnK<`Z2DT+6Ux8p$iGf5u=xiFveryV;l_PL!e)D88sQGg19;q6MVOzLV{ZG z90-x10VbXm`#^9=X$h3pb?pa$dP-cI3FwLz?&JO>kk5*HNRW{)H4{u0tL$}an68E% z1tD2SB!@sDIEI-3A-of0#oE#dutTu~$HXefHXl?hfu_I}7bC*h zMRa$T;x#KMR}@TZWJmQeVQvZpPns8(Kx%J-ae9wN%<2D!XTI^JX3*SspYI_|0cJal{q0AbA4D(6I49W3%#S_%1mG)R=x%?+k2Clq5&Txzx4~?O z*#WZ?W*5wEnEPN3!5oIMziQ;`H8AsGYMI9{4KVgs4od|Lt68^20`5cJlMmoXz728V zz*Zg!*M5H=a7QEfe$XE`{>U-d-$eLlIJ;nW!`R<(*qQcfm}?^8Fr81rJP-3?1Yd#t z+X-XK$%gX~aGWYvz)*zB{*JC`Egei3A+jY(bn#~;8l>6BDi`I)e! z$0QE~r>4$N4&dd&)6(g2fL{;BrjNia<5MgEe(ea27hL(&Pt&v(ob}fUUH&Y|MXN1xxx1 zd`*rmD@_k#havfy;Oz8qSW45q=#EO$AH9gqXD3sq{P+PlgD!dc`1JLcz&@!g-49rr zoP18|{L}sgn2G16&i>|jpi&p}>`U?zLy`U@>E98YmriEjTJ}Kj>t6uzy5^&g_pvmG<^d>`X+gPLs9<;kgU5n zJ#`Y`BKy&0d|P@+YE~ZEpR6iN-v~r$a!w|_kCyb8<@o@q)?b=BrD+;0XHH6;GYe&( zJpZ!vPv~-y2`zQW%Ukf8nVkL=y(KTZJbk8Q?dAXYJHB5qIXx3~CwZmKl&M#w>xj7G z%G8)2H1K<^cr8uu{H z8Uy$w-_xyE@Hq!nHTkxnJiQr~()4~llV_Hcrmvnt+xgSdzY)s?(^Dl=kkO^d3umNC z!sE0}M3=xCki4ieRq{UO_xPEqlId>*Dm7uxA-Y^VD^;@pM{qf-G*$AzH%L;IDw)3o zma(%_6aR5OER*M?$03;H`E!#&buyTjD)}?~CQDzRzC!BP%Y35P^2pxOvde$>7Y2OB z)#)|N?#~6+q>s`eeccSaemk&bH_X?sm%btWC@iI^6J^v8pZs~*8_T{F49%m5#d8_Z zxNB4ApZOr1Ce2TtUz1)7Wb!T-$`QVv2o|Ky`_56=E?Jm9A-*O}DNVmfx9L};&!}c- z7xS5XBB)JomiG_H^Im!Wir-6)Uz9p`DN{aiaccb1TVT0pNqWrd;Z&NsNNW4Vw&=5U z>5Jju>Q3^KF{Q~V_37!PPIuGkuHd@#JxEe%`VbTL!;+=RpdnTAbIcx+rOT2*V|wcw z7DlSmLXqJR#$kD-Y>>$X>vlCny?=YFF7%nI%n6Z=zb>TlczML zCj1iXD#?poU0Olv)akpo((45^@bFwoA^qS2hOs@#R)$Y*UBuT*o6|4AlDx{Ksx&#Z zr8J#hOt%ZNsS9S`0Y}u{OOYp~>4nUh*RM#gl(!jmczZf%O`h+*d^1p`$#<2kOy6)F zJ=~9H^509YPd`D+B{!r>w*4CT(&V2?R;B+ylH^B|H>S?{4|XT0qi;%$Z-0f@OWM+> zEu|&1I-O*@N?z8UI_L4n5XuE>(pN4cd3w135O<_X&OJ}4JJailOkUcRDtV@!REbiI zBEc1>@_E)b`TYFM0MEWkJ_jcfbIy19eBoSTK375e!`t{Adncc*|HbEz&!B4$x`k9Q zd^ex9XZfT~iBvERT~I1mw}Q{kQ%HY5M%z>{@daW&bvf3rV5j?bzL zpTClrZ|bFe*O&PG3Pj3M!5LT5zIrO3KiJRb^Kxa4(wo+j!2u6#Wu z`S!7&ljgQ@e6CKCCj0>HPY1L=_!ipVDRF4Li1tHI3*{a@zw$ahH%N{(O5WZnss7~z z`u+V`bbY(zz%NkvsbKM+_=Wj3Kch7u|cD9F9kUX8370=VYQ1bH;iPgmQ#N03S zq^q6w)0gx4ZSng#$;msG5Odqv4B`8i(tb$t=c%vKeve?z62HrDBxdJPK41I~KHqj5 zpA)1;&ApQLeyJ^=SWWvc%LQ{OL!NdapRY%Mk_wt7v@fip{UGXnDp)V{ThRfef_GK$ z`Qa3wvwp+pPXu$egsiyNM9`__)BS_+ulRWy%O8X za)xvCy~O-N@@ksYasR@(*o|u`E-nzHa{*LW@&X-m{LBjvHcMx-}#QX{I^^IGI`QA7AOr6E& zucdrn|7qIK*u&?)OSxdQf&Cn5O@H4;`;GhgoGWefD;G0e*}oFASYrO8iL}4r4Sc>? z%I=h((%vgI^Uso^_hgBA>hpZof0ECi%;R&agz()980I%Rh-vv4pHD~)f8CR`|5^Gg zDjZG)Kl(l~n}5M)Z6BYTKF;Sg|HS7hEBHLUhtKC{^ZAbN@cD+j`0SS)_~rQw=OP(L z)}BuMz#sYip?u{p(v#mH@i{b+ln>A5bEus(ZKg!y-Vt0Q#D-= zOHDZIX4;QQK6ihM_BU?hbNAJJ?vXZ9aS`pGJ;vuusj=S}Cn=R0^_{O0fBi;2pOSiY zXff^cq<{F7l++(CCFX+?!zXspUM-`{zy6N)kL~623m@dO;ca|QeJ7v)DQ#_=JWoiT zzfJ1u*MCUY=_~o1^)jDdy@c`EQ^IFHAf`t0oiYl@@(nf%xBx{hTvkPu$1$m8i(`*~=a#@kzG9 z#CwL3_)^#|`9>9Dmf4Qbg0a^Eyes&>=K#DrxRrsv zC%E82fStkR=ucDc4K5{kUvL+@%J&E4ILqz{hQ0}suLkQr2k^CEGCRAk2S2F5+mT?( z?*YCMyt5qOpMvWj2Dm@?1KY*XU@|k}n?Z))pMx7SKz=Lu)V~273s&;&+rh`G0UiiG zvjN~c!FL(vgTc@K3*fuKDz??*!S%I>#P5PnZ2|J#C8-Ml-c$0CGXZv%JpOus_m-S9 z4d8txOFj(n{*swY!yP4OzKFLwOHL#BK*@SmiMvXE$a=i1WW z9M9F}59Zz7$FYD}Xg1xJ00ME5=M=HwJZN3f9?i%8ImLROMzq{rW zc&`5#DoR=JO=!|(8y@8sH@*=?R@QeZ3c9TSbfl#0ruQ@CfouOB&%t^$lCq(DF~F2< zddpfw?Uv86DZY952%bBFcN_<}FL?il0KOJ1-fbeCnz{{$vKnlkrqcI3jv!83N=|3& z?$D3=TF7++%nRf zcf1wP312|fC_De%eRy8*CUnbX7aqG3&xtQ(@VuyvNxHZKEv)R4H~s+6%mdJ;&5!>uBjto=oxE%Pa-hr>ArXD#9&+;dKg6E7Ml4q&7 z2rav;GCLlanbqe4Gwah|g1zcp>;q;WTmsiQA7X`@ySW6<>KgC}W%G_9%gSDV$B%%y z`dqqR^PvFr*FL%w_W3_#7T2tLFYF5*K-Q-gmVXY<+Ut?GWsCl62JDM}!s1!-SyrFA zy({pn{}B1I>!zc~Q%mo>6VHY%n4y&|`{|{yH@*|&dD-&y`#>4~jB(EGeHzdFLH2)5 zKb-)Y!kOK8Ht$H|*>aS<-HKyBhrPA$04P`f@+h9yU%MWd8@|M5x#|>t@x}yxWpDZg z{kGkf!gKXUSnu0sFjv?7=2|>E9=Zvb&Zn=#v+Hf-p4J}!BJAt7zk+A?yIurMPdE?u zznl3HJlAjH2-Z7$81@Z+S&iq$N1E~MyWkCY_UE6&^QPV83Wvsh1NKd8kfPM^sxe68 zmLJ^$`z>GPsCDasJ7C{>?pyJ^ZRoT3%A3c30ngiKp${(G7EDFwT=te={$aSkHFyVE z(YFP6@5bBq;In8`skaCJdNsg1fh|9l0&yMn7&gWnzOcnWUs33emB z=-d9`1i*WPG7LEA+g>RLcz;k!Zt9NU?cc=Pox$BR@b-b=Y!>QW!Aqy%ZC7yM2E2VR z`0HN~^oN3Pp9AEFgST=#*&W<{5#0VhST+}6Pw?ft0X`aRs|L6yn2$nE?G27xg{15Y zKJp77KNfrt<8j%?g9{hp?GwRO%)$M^zo2_A`(zLf;q6nw9)Pk>2jBk#-VOxGF?jn- zFz&;6`)sg}&FJ1>0?ICRF!;mS0G|ssF9Y)P!4>Qyz7VWLy(zmd_&SQH?2Eyoe+2l4 zU<)h9mxAA+@s}M6zSx4de+<4k4R2o#rauAjmEffb0EdI2>2UjMQ2B0vuLTeAvtJL| zAAsADAh;fH-w2*YqRaj%cngd6{-6_4LNDKb2EaFirr*KspM&aYNc*>fhrz{{9Se4& znxdEQn*#7a@GchpcY^ORL%tUr-Ujgf;Efdk4+VuY0e%oHJM3UEA_ zJ`Uhtf(!l=;77rxdVn7XJO2aVk>GkZ|3`y<_F|6(|5b*!{}XI(1b95CXJ_=YU<}LQ z=fN}#mSs-_&m*%^PX^cdS|e9(&m3=q(G&Ag>;90izUk97nMg1mtANtbNwvu=7(>qFD_!-{bUGhcN z(f5@cz7XI8C7I&@A1e9Get?gZoXTm%JtY^j>g+Ay2$b4a@-?P$e@QJ^F^pt?A!qQZ zl6zkO@}ZI*X3_DI^_u`5DY*?bA@x|vTiB`mw&Y8!zt5FS<=6jM^3`YX_Lq{6cOd9@ zByZS(w|6FgMdos6aybT`)O(XZV?DehnRr&ym^$aa??PmIa$8%ND7*YN)PdBD2}zJt ze7P3S>t4rZvh>gcc!u-ejAw2)$|hBK^nTczzdRAo8|SdMf79TnVIR0|3!a1TLSCna zzQxM3=@%czbMu;6c;0*&Bfa%>=EH4E{)p$c;GTB^yfx@zsBa5iS%kOu1zVV5p9z+- zYyW)k9#)?(2H!3P_=n(ex;+rQl^xx~!FB8!9t#e#&HP*N<K& zaWlo`%|Nif?BnOen0a6e#gSLQmWYI0S-DCa57m<=gZg)2B?5g;8EMKnR@@rv59+r3 zJ5cvhtb)gYI-n&2S;3M~tYE1z)j{!g0uL@d%pKt}IgBaG_rJDssjO^;LHqQ4-RgY? zIk(V{NFzSQ;CG9B39iVkak&$qQNuW9o5wE)Z82{V?rgon1GG(-N}%mal>qH{7n2WL zmmnA%w{BNB`g+zHg7`i)sJQ(WHvo<2OBvhX-#-H#)^aas;;)NAQ>NE6>gPS1rSmOa z9@Otwj?9|tUI49it}$px-)BL?{7!>Ld@>TW(M1}nru}INVn)Y-wtJEB9jCqu+9jS# zn%E{Ny{+dNJ7}K*ZaVbqum$0P6Jm^~M*npOHETU;6JldlBG#?*7oQ^BT93Ok_ZntPnp5%*CISLjWWYBk?NLuZW_XAJ^Lb@{xVB2vI$0&TjmOe zNB899t)O!S$c%Xw%HuZneX7m4519WG)7V-Q=P^84*!DwciYS92?)J3sy$v)~l$Z|m zjJU^n%?x43IMIeg$K%{W>6G*YggRd?iEvUcnw8`=?|`Pf#$jNe&U03jUr%c|Uqt@}ut>ZV4z^o_ z=YSm&t!IE871KG;J`(nzcL1z=2@*l?CWa z82LNHz@As@&IQ|`{=zxcM)h-A{#VpPtnnuGnm^KBRrhgt98#;X0p3=h{t)b>y1E_M z74-}i`X{v%tAAU)%3<@D`ZRo`?HTJglfhP5vuJo$ThDuft+5`bIooVaUIcXB`ppHf zFRjyP@$XshP@kW%dH)79!EE@+r{ zGHCd6DoFix)Tz$v+9KR1Wg}?Z5KhkfUE>Jse_<-HA{iY77ju0F*pK3yRbbb}^YtM2lgO^(Ugmbv;RtAQG9ahq4bKX#%4Fh{q8P9G$s@&y% z(=p{uw(zIQ)58(@nR1$?{#>~f4|Y~5m<)DK>B@EeSIVhMK$n!)^TEDW7SOJIqnv;l z)`q!H%4$UT^Yxl7VDGnjtg#ni><0X+tMd`Ra$KcOQm74QS8@|p{(ktDI9~D zGuWb8li23j$;}YXNoD-#YMA!faxc-U=apnp^LH}0v7HVZ1+6-37Gi7E_XhR*Y7eOY zNu=2Ve(DEW^XNIyz#%@ML8WN|YRzPoYMHM_$-o#x{?L1I*$8%9>y8pregQ6r zbNqB1K6*NE{gA$(5#zEzBM-L#ZM+mZrQK1r0`j%_mf=YCFUgI`z&D2?+$fEfs@d56 zpwYLwfc8k)20HK{wJPboOUC^*4m}ARFquQV*2rE)Y)m1oP@7L^gxWrN3Tf>wQg1u# zWAAocG!L{>SLW9_;~Hq!`z&|2OPoN(&SQ^sUmPU#5_*4i2e|40JkeI|NDQdYYimG# zceewr-cbRqasMEw-`PJw{lh*14H)yXQI=Xi4g;=z|2fd8479yl(~Or8jv2{t+u#CN z-HvU&4Cyk}ry#9*Qg_hc8()AnY{{N#pY)F*(d7^7P1k?WvTVU(l^x^ea~smGC{5k) zkjHIIRa!h3SyuTIqsr!ey{7S?9tSPBH>vvj2JUNHg7g6!#u&I#uXtczjy;%U&v$sdC@Y4;^)vp2&* zo5%kR8Xd|UT6Ly9ZrzEVE#`+Ipl!a20d0GuBWSzk9NX=q7lI}>fwgu^{hT8ugWpZD zWd(3NW^d^UTF?=VY8$he{ruEy^dDvldxOE|iI*3FEfEtqR9A>ISHV_^cTR)7DmG36 z+as1jF>L$9de(lwm`#;GDlW3-$3*HGPo# zwy+^=rpOxSjo3O@sc|98J_Q}Ip#$iovu#0_iIwd47e%T5U~9zIEntP>8VAK@k$44c ztC+P9Y?t`+2G}uCjccsqVmIe_ABawz9DFGJx*_dj5kwU@Ep9vk_Jw%QAM79Xo7ceZ zS;L{%wnes-y+)BL{LTLKYIq5>(v0Sym8Wr+qDrej5w2QmG^nrV5m3K4G^VX)L=Vtf zduM}29%Lgo8AKgy*8Ci3bbf8n*8M#|+t#QLYEPOEI)YyKB4Jg}Ul z;e1AX<^wiMlzI|ujyTZ>>^ZS|6WAiroc?RM*w_zfjd8%_W6V(&38YW#IGhh!hg>_Jg-(+Xpyb@&3lr*wDJhMXAAwcg+ytzsm*{v2QaaY{_t_JkI+n>H*Ke~nP0K4w?=igvIxdpumcGGRr1h8M+TB7Z3x7?n_ zxYrt?^3f%Tuk!LRP@i2KNB+swpXlq-d@B@%lhT=GD7&{DCBKt0z+gO)x) zg)B4dXV9|t1)${?(e#uLx(Qmr&f!t<+fP8f4hMo(>R|(|Jeb9=lFDB7p8gNQRd2J2 zt3`6e`Q#UZ`i`TGsUFN8tPy`7)Gv;T>i>?4aDd-mpf!7PIv;4^8a!wRHLaGKZPdzb z9<|ur`!cA+}Qq`+~db*VbEnP^9Q07Pk!ewV42QBw4b*lUa?79lu zLl9GOC=|oy)tu(G(vzv6m50+4R@uNDybDr5t5%@duGW_2_L&?E>bpZhOpShQP5)I? z$$%47oSMm$3~c)$gxqBVMAqM7~-cw87@~pbg)v0NUscu525B#-~S>9*&qM<*$G?J;3qZ z?28(p&G&Hm+G5x;grg&9q+5=m9<+Kb4zzV7y=6>1rwVPhQbpUw%m;1v{12e*+q3^V zWUmJ8SQ@Qw>-0BmMrU8vu}gFq!d>T4le%q+2aUbE7PR{xb3l8{W9#)y9S7R0>palj z8(ES*ol79xS2+wC_vP!L{Z4WH*8d)N35cHPbZTwFJWjt7&vR*!REqkS`~`I-cEBXU_-(xO5JJ@bDYGr{2tY`=t zq>cxzQ)VG(-KfE!VcV!(5f?jvHuPp{lj)a1n=fYxS}tJk$9%mVw4JRYXh-ZWpd9l* z2JKq97ijn4-+}fjwFtED$~vI^U*rfJ^uZIL!$N#P6GOQ{G2$q57&-rQ(9G{&0L}8C zf6iG>eaN-ZR2O9DAw2#-2Z4e>#z&44nU%|GBVYk4xi@(-@?Gk>M z!1jwS)P}>NEF1iYnA8C5O|g(GYqf~J0guu_`ay|j?vG%#miKU zJz~x-u)ShG^F1QETfvSBZMu9+IOfYIM5ne$I3>>UNnePK9GaI!gXLg9iIrt`v0XDFw#eVwuX<{7<_Kf(6redZT5(zX* zyj~J)wg{&sn=5v*yw8a}to{Nqjoq+F{J9@&nTTcWUKD?>09!7;9u4-g=uX94C8})& zTO&T^s4f)2Y}NJRP3Q}J^_y(hO=9ahuq{GxxNH;0nAr|7ZwJ^;(eV`6ZZV|}*j_Q4 zBV@m@eF1hzj9>%2E>@fdJ0d=t1@@NMln8cA)ISV%T-;)2?}{{5`hC&r0N4qUh1mc$ zXun}KPl{&8z&;TPbQ)(wIKBI4B9ZkwD}G)Gc0nv*IWLNj*sYgDs0Y|LViYayw_@sf zpey2S4z8<01c6->er>_7i;H~F4UyFu?4~%+O5YMqX-991UI}2oiwr*Rj_5xP>@U%R zmf;_9femtBoT0s$qI}KKKULXA-!@$tIS7$6l!e?nc~*&Q0W?QxrGm{P9aP@sAU>>o z7>39R{)UmUqFvRH{XRT~fAw2lkCJj5YdJX-GBwUa@hz;0I+Z z3-P1!N)ND~6n9qTXJtLr?H6S?bNN+iR2P!JDP!mk{!sqdjL1Kg-tEBtR$gPL{-Z>5 zl67Cnd3S2Ai%f<~W+6F7pAJrGEY#*lcwxD?L}8#)-spYJw-&0`;x# zV2jk!6Tp_JS4V;^Rjo8`FQ{ohgT18I<*aLk+JTL=QoZsIB3G-iboOi2T2zL0>bbID z8`RhT1bapGX#)1D`ZI6eq6V@dx2XfDtvgiD5kNcDIaK}KY6eHgUiJA8!S<{5ScrqF z(h}^j`mq<-5p^E>_ARydD6nH{E@xlI)v@g2_te5Ei2Ojk-U94H_3ID7K34m)Ay27= zbHUE2AG41>Q#Y~FXVn_Dz`ju9Xc8`{10%pLs%N)=T~hbb`hBBjzX$ZKdWG$IMfHM* zw_Q~)WCLAOy=W}2tNWJ&-B2sO0(Mi~z=pi7HVp;)T|M_V*q`bJ4urqeC~D+C>KPio z`|4qeJZ%l<5@Wix+>byrtOHWPW?64l2Age-V0X;3dU9&F!20P%phecZGrkrO zHS1IC;_KFZoT1&YR(TodruDhqV7ILC9l>r}r&HN~w=QW7cE|cTmG3WWb#~)j>(!+| z_pHD0zR9+23&5VXb$J79nyu*#uvxZ?$H8XXey3fUYx8G^KWEFk1h&BT1sV$+EhYw@`ps10K~j5UO5l;mZ(dUeMWrI$#`nD z{d{UbDYk9RA7}vrOTsB?_tw?2u6K7l(!$QZt>2;lFvr&Q)+!^12F($2Ykn3@=+>eF z#-Cesg$&%$>XV+Jtq-7nwiy0Pl`Yo2DQNF@>p|mBvdM>DZVx(a{7TS-#eBIme9$f< z-%9;yCSuyLJ=%0R3W>J9NYYAnU9`W42z>oy8rW^o=@}y-AYm*bYSya*8rXFQXwWfK z)mE$jBGB5Y$iY^pA|7E2{`?4N$PNyZy77lV>&0IK4Grd~2=fmE4gZGg@aSHi2)BH1 z4`_#g$)Fv>J_7CZ8^>$sRq>!*u5uJ~>reUE0bU4qU-}Mc-{;UEwzyZR$o&ShH@evIXexm<(pqs@f zX<%DKCiQ5msKH6kHnDIkBDaelD*^2ml@0*y5jXw7_KLCW@d)_0c@ytBXFB0;r-q!;NS!nH01CTMr`F7KERHBbenH1Cslq^ zX)*#XP+tRoqUo&No5mp6mxT|#_c3ULDnEcWeh(99E&tF-R^YI7zJ?0FTp!{32X28z z2v#w21gF*wf|ekr;W&OLz37|2(e+F$+H4wCIeRh1iO`KG;zr{}NFeDhXMMV^?)|V;Oohs07+GFc-8}r-`7wpPLTaXDB86_No9H*P|n7 zzbjnb$M^L`cwigK531J`bnsfXcWH+1@wvI%|R!Q z_yhFGnNvU~@$6%~a)9Pwik&qBY>GHS9hf1?P;Y07_o#QXL^GQ6XGPe3u-RfVD>+Bx za)mWlWN=i>7X{}H{i`})9U=nnvaYp1^Dtu9h^hXFC=@~U!Pbe9O(3*WT%sM>E#g{% z?G^s7gS{?xa%3M7A8rSGOW3&4aZF5E286G%v6SzMW~|HmV!uDw36VMp>?1Lfqy41l z{2I_FV#y7#GvW&S;xm!-4$xWgJbU(tS!fq}XDn_!^yjDaYT*;4x zuN+wtw90QRrS~*yX4U)eA?y=HJ@nmo1ho2ic1?}a)Op6aPd@}&Zynn|G=s)2Y`{Fw`uVI?#7fTPBVS#La6>3z zP&1oX&jyWNv=+4GsF|RxKiB{ob7KZ*+b3zi+FxM{cKC-mbZl4+v`h07pxwA_Ve9@1 z^iONGW_@T}TZ|=bdB+agsq8Ay&Jh?hnna~9>7lA=UeQC z6@~Uv#W#opEYC(Un@05&argzWO`^pRur1;Q@7pR~WMggz}^zCvJ;Mr zWwfOq2(QjyCq%YC*heDaAlOOKW;ocVBAA`?nb^hs*|TC|d!X~eGXU(8c%MVzYtgj> z&}DJ)JFx4bBm49xv6l*ZLoB-ubX%mh1p8flFaYdN(Sy^|*~-ftb90m#USRW;C#mBL zl;a$aOO>&-N-rzh{{ma73{L`EtE6yhUZ|XI4YW;JL?zs=e8jTsP*U0QyOnpSd;67z zOgo@_$h3pX6`I^P6fcUrqx|&}*t<&1n-;wb15>_5M6GZeXdU~fpdopOLFb7|zX!nY=q&-_uzk3hb3EFr1D$sttNeBGQQVslhCFtO#?AI5>$L?S+ zide4SUJ_&2q07Yy)@_CG9uBrrd>sO|O2lP=trq=if~^s=e8JX=_&s3jL@xDcy?7}X zY=cNy3${_rSq`>I1gC+$Dz359wg`6)fUV;AKCm5P0QX#WiZvX4yTw?#^L?TVTk4=V z9}f10NaPv@TWf3@eA{{qBHt3vc!Ql12{B-&#m7NlXGD8Hu(P6KJlHvLtq|L{z`>2WX8IbPs-=P9p4|*#@-cQMOUw>-6VAQEwnz z%eOmd?T_f8>XeNJ4eq@ZG$j5sXx${vOzRD0`-c8K12oKs6TA%8?Kc*TdnmT-WB6b?Qau% z6}0U-maW}ebc*fAa{zQ0PQ~xo^cjRZ&1(nRc_&Roms2We*DvpacGI5K*047yUgG5Hnz{ig5h2jR+6^j{Q0GgMUDWRbhNW=&J}%7FVf~Q^b0Iu%|^; z4z{Uc1GRpd_-rEBbP?Se3}0#-2{uE7u%%~--mJ)Mk+%hGj>r^Xb448=FnoELg?>&% zmH?YCCiDecAbhC53&pXw!4`>T3&0kO{cnLS5r?aRJuik_1Y0V~vgXUgXzIcX;@X>F zFNzJil6UzYXoZLk1bbOLy%lVwh^JFoCC2{_v|5y9E>QAUz}AWnIQ=XXt=Qu0#3~Nq z^`Z?QyFq;UJlHE@9LL=zk=+Mui+F)(t2oQ9+a?Y(&+TG0*-kO!0N5^p(+{Zf2af{n z5n)uE{o)1c`T${BHssuj7Fn=cL0*l-Phuprz# zjb^KDYy-r!8~+7p`vOipJ9MM+bo!1Hfi9L`5$^UB>(w*T9pTg!RM*|skyMyH*4{Lv zd##pCuzl9BPGI}3)oCFQSpVS0-f?T4cM<+j_pOO}U>{f`7J;3x*5?TO(CSwP z=p$=3$L+_~{lmacS_fA|+9_-1X`oN6SE;q9t!+8v&sYz!87^Aw94=p3PksmXwe?e` zePb=;PRnJhl_mSudX(D?-&rrgIBG2wb&ut5Ub_lts}D%qpJ@o%d)s|OqRtqU%`Noe z=b%MjE~#AkFGy8c5&-I5p9)@e6^CZE+$o?w=jrQw53rEc_YDQDpT13C2?&R_E&vUS zV}pk0aj4e+qBLm40V`r6gK01tyiIj$SOTTDHQE*m+Bk!gr>N0Y5pFVu2C`{Sj3TWy zT3*@-+^TsJXzTZA20KLY8J#MO=ZMaV?c9mybe0L<=ddSO{kN3H>q{`3l)S5YTp7K6Gc@T8_tR3xQ zk1t@qPT18J^of$cf=+zCCFnHq0y+uSs&f|DOfi?%_*v0mCfFRY>=4*Iv7a^pYYtkg zg<@=Tu*KqPEZA}pL*x6hX!#D%DzT1wzDB%~3RWm=<-pd9nN+@w;@G!fn?xZ8#}4t~ z8nB(B`(Uu$Vs?G7z2Xa2bH7;L8SJ1~+ZXJxc&aYg8zO-s$Hk$BVDE~l)xka%{VIc< z5*4a}ofZWY`9d6IGhGn9bHFZ(Dr>>M6F1I)eJ{Fi0Q*5)j{^XiLfURschL4Lshb^QFbCJ3@v(9u z7tyDcvDCsd%Ke&1{#5xO#L%;9UvW5BKZ^ap6<+)bbjuFV5&c%1n( z@_z}m@obv@dE(DRfagS2>hF9Jwij%Hc#TeCp?K>zphco|EwIHRg-X9fTxJJ7FIG1J zS}JncV#~w|HsTAy^9`_<#9TMdVO*8YHkK8Z{n@a8%RNpiLLhJ~U6=2O1p^ z0NQFl$7@?Jj?oTFmLlA#6#Z}4Z)+gj-Giw;_k0N2dnfB)|DN_>L<$#~Q$*nffTzVr z)a+%V9EaBnV(mGw7sXB8#qVSdmWwN_@(NKW5A0>(6AZRegIwTH}pkD}Bi;BK&!vO~Red;DA^V2y{@a{s`=l zn1H_3bfenA9*FR<#e@1jH5N1?r4DH19|J%eOhz7>T+o1Sz_lhZwstvs(DqYC8)?ex zZ0AbL)@fMjTgqZ_9KB{MY16(huKGUq0JZ0PSuAQz#eF?E&M#Bt`DJBX&M#Bk+e5!` z<`zaL&MzzLuKEMIInFODC(kb{Z=7FN!Rh?6it_w2FI7}}?D=Jtjq}SC_x{>L_4CWB z$n(n-_p^*vqr8hbzpSb}zpR=(zs$#7KflbVf;_(rCrQ<0E`h!-=a*TH^UD6 z^DxdYtNw`d%W9|re$MBY`OEXmWK+uX%L0lyzs#n62TqNx>0Z7Mn>hd!$C(8>9cShi zBu~q$B~Qx>!fAQ6-3L>8fv6)-!3#D{!3%LY1+VUdr{L8q{uDg-Q1{6!h+4uXPw}hi z{(WD@lvdoE#W7GWOrGKwgk$q?)S7W@UU)Ib=9P4l$L1+Gmdz%QW%I-tZ2DJNC=>OqM zo;(rK_L$#?R$mm2Z?yVfqp1w|ycxnl+emA@(iF7zMo?Rw%}@+m@b?Udywd{l4MGs( z)-ZtgHu49xHEuu}wG*kfCjA-T{4Ql$oM%4KU+~_RV=2=rlDW06#HV!Zz}z}Tk#=s( zd%N6bNxJ4xzFR}e^vH#By7l~(0ml6{pl=X>TbTICaS<0zANf%%N_ zW)5ThC^N1GWyVkB6DRyk`ot{CJT;VeO%_MNv|fDhke2^z$FoSq{Fe?aQLdLaJ5NylNok2oNlRQ3me^CCTMBE2`8>`oE#rJ{X<3(ZOUp@%UEZ+R6;zxzsLH0e}~`KAFBKPfFi$doLgG67{4DV{eF=2`?VZ?U&~GU{o2y+*KzUt zwHO{jg&EzC5=y+{w|GRi%UUaJLyJlDg?9 zlByMKx}%gwliDh4?yf4`9VVs8t#q%a48pRZXhMinOL?9tT(6uNx=9svcUDmksiOMK zP?a;o5>i7-x@d^%JTolisv(|ILrNPOQpQO`%1R9>r;75A)sPB?hNw<6!-`TvR5>&B zDn>&pNe!tiHKdB6Ax0IXhImU2sp_I3-iC&#a%Nb~&=8+TXo#;GP~BNWYDf){O(`|R zuNV!HGedvpnPGsF!j!8iZI-{BrKxh3hJm4pyecB#`Q>68?m`k~6tjk)) z(^X?jON}jKXlz+0jm1(&Ka07%ibJG*uyDmWtAokhM{D%39`z5H+PR{`rkU3=UQ%Nn zYne*LXl!Mvu~nqTdOK{Iwj7fhTUBaoH5ZMo>ac0XTE@rFSl>rzY;`rDhO@@{NsX0F zDK*yr5gHrdtg$tnG}a?fpZTl)4tEOS;?I(%sgAyR9P^KEcwBh8S+N zu8SM3_n;dMeXJV|D@Jt#%x=_Sri~MH{j{%T`y1cNR`|o-BE>Ez6}zHTY%gcUuJjPa zb}#Gj-0r)Rpk-?5@(xwkJyp@NU7j**GmafM9K3Yj|D9vU&Y{k#9_FO#Wv$XUhdMMItLJd3-1Vh$M@Z$a59N-O%H2RJcSA$D z8@VWV;|G;H>aoh*&j!G|4T8>N{R<4#TWmBGN!&Ce#7zdwwHkC7xW`-HZw@Yot zS?JB>S?Dc{v(Tee(NYzy~5Te zE+hQv<1F;9&S#-_b3O|_Ru$dlS?E1f(eoi^q4#>oS?ImxS?DE9XQ6xiOJ||?bua!b z^f==zbfXeD3%%dt&O-0+d=~nEV$MR3cRmY!pm7%ZAY0K{=z|?+p${oK3%!ivEcBuB zEc9XWEc66<7W#14v(QT=>WBFoX8V8oXi#JAiMJj92M^~|jzyZiQf0Xus3N_Rx3gEO zD!tOfHj1k~dUECCI=S+dldI~+Llw1&;qtAUY))xPQaIA|YqMhAC_)O<^Nx3d7_MYh9PWg=lOxg|^e` zgii1cx6~;2UU-eFR+SkK2eP{7kgDz#+-ETnb9HSJicMvQM~rZIM7dmPBHdzB=@y$w zx7ZYJvAJ}MEu>qFHr!%M7q{5zLATiYv2HQuLAR)uv^geV*t^DDU;j%H&o=TeLCQ$a zSW$XLH-~40Gu8hkq^D_?M85kMxZ0(ld54JmX5X=-cQ>eW&C& z;X!L>SI^kR)iZXLp0S&|(|>xDlYT5#`myd0^J67k{a91@F)wF7=Hcwe=)0sJ>!pg` z5AkDt3_n)av8~^l3gqo6{a7jK$NH)zN=iTG7&edoPY)Utbl$`c%+m3n9z}kv=s!I| z<$rpFJ?1|>98dm#{Z9{Uf*AklF--cg1nI|yOFx$A;>Yxt8`{_DZGJp8$8<21@e<(? z+n?G-Zt&F(*fkoRLHcB27tpEVVrQ_KqI*}cSz$bBV{ zmY{7S*qj$+{PILGKdOE3*R=mrKb%!Q!q*W?p z7554FriRshBdFTU@v>I#G#0J;oL<)c|FmhVHupDXcE?zpZ{e@6Xm3=%7d6$YvP|xB zYy>*b@q&ywUMHtnV@x2ymSXxEphU26Krk^!$#-GXCPK!6Q6> zLub$5$jS4UYb@8A4Il8VQPQ(Ek)E}w^sG(bS({1E+FW|p7KUeycJZt&AM~uP9_v|K z7votSd)ca&!%xOYKUvQ3lWkPdRu%1}pKSj~Kj|j@WQXEckkioo@RJ=~{bVOsKUr4# z$3MsrqR&G-Z(qany1RJZQquFrNzdC)Ezw_kUWeKi=XnP>R*-!6Q{;K$A6P*Slq<;U zgB*Tvu=ImNq#yK@esHLZAJh!K>2xmJzx5?co9j7VE&ro0CB|!~h7Hkt-UDAy)K4LM z@WeRd%rUJ3|KV|E51vzIoCWbedqZZE z;|oR)eU0StzwsK$qxjcI9{<^EB%=y)r}D9{kv#sdy+(3({AH)V^d25^T~{7J?a?VBiO}zggody>ORDKcsO1o)hot(csTxw6MrgL^jD81LyiA+ z)ZQ*V*W0YN*!$AoE|rjKThdu=OG&lWr(mAC+F}jsXqnRTO97t7ZhW~ivSrH3mMJG& zrYu^fylj~YvSlh7E#u|VGL;@|naU4o8Ba&cRC#2}c;an=w=rGvlrQ_M$`@mD{UYa$ zhJ<`u@ZZ_Hkq_117C829JmuShe{b)`$W4yH$L`(8MydB-*t?N0`y-sDY$nac%l_ks zF+uUf|B!00>nm6t8wq&-uWuwYkQ1ba#ssO6DjKUIN=}fPJaU56R8EkZIZu#eFBn_w z&0Qx*EnFu^(Q<;+QmxubPLO0S#=eqGPLNv53DQINm0}(~L24r>NNwfTL_3$Q3E7Fk z?TrbNjPNUq2~r2=2~tPr2~sCjbe0pOE-LtZiC8&7>MkcpJ=79CaCK>eePM%ZNE_@YZLq&#g9BV_aLos8aNt91aM3qjgNn1k=3T?mwH!-U z$vWp2h08Q5M%$muG9W`J-L4#s*143?w^M{*39}tbsJp2 zXw7VV;VPn-HFKm~GdGZH=7x?nvzD8*!Hwkpd1IF~b0f!^S#OkjQO26NiSwFy4t}U0 z*UZ(MssYWM_s^TlRkUnMxqsfGm{qj2!O_k(*ztv{lGwx5zmZ(Z@xl{kS+~Z;Z0oj^ z*0_~nja#cCMitl_*8lvu?IW$RhqT7+oUO6k)-|kgdsl1R!POdfl-9VDTD7yZ#xfVf z8h4S_*s)w~CYP&G|N3&(OIqW{ZxlbUT=j)DuHL;iYqmJ zJ6Zd-q5iMuSe7dMQNn=2KGgNi&zR{Q};JT8{POe%|rc-<27PC!{6{7qAEH{f79ua z{>JedvGXHeBX)81H(g!*O*iRpVx2cL9j_6)%ei_Fm$|y(l+@q{UL%IWJ5+Y|4lb_| z|IN+JI*;`ZacYTv(mObMvpDb2-{Bo-NQ%6}fCs!oyu&-RlHQ@VlXn>C>>UQFRUJ>3 z-eIt_cNk)LhoL6#FwEf{@I9A5@rzr0SF8GPhj&Pn-XTePhh*s;Qe3=4Y0P+Z?@-3! z9m#+QOJM& z!cX~mQi4UnXP5CwQ*{i;-qb$$y0-z^A46Z0bH2QQf|_Y67j3Kk1L{)ppqnHQhS3j^9x0w3Pf z6f*p5bSuh_avu2f$4AOt^0rv`i81QScqx~FF!M(i7Jpy;!}`ffJ{P}zcgRIRj-T5y z5orwaV>ihK1z0Tn9Klbd`Lyv4##anHr8KJB@z?`_EN!y|{~CG$hHL(czc z)B_)xMp+r2if|cx*sekNiF(jOfGOa6W-k`OdFV zEgte=kd<;VE^?RGtCl28XXPd3U{bWcmGK?It(NXG5s@-Tu1Fzp&&F2E{2+^^Cc>X0 zkwxJ6qiry$k!ATntEDGwjJ#xi5}P^gDlgS|Ds88Z^(WIt>R5jQ?V*l!LE1bW>xPuJ zO~)KLx((AY3^Fd-D_&?pjngLaQngy>wnxV$wRqYX9qR?5Ezz;3#%VKjTw3F_4?3pB zfbDi*S_XZ*ldFd1;<(naUNMee9qSe0IMs1QjdMKe7*jvfrCLmih7 zwZOQWF4a=igeYIl1=AZAU8==sI3r56R4+>n-doPhX;6CAAt!tXN7~>LX#eDV@*HG2sR#EakVG(s{q^ zAB&};R{kTV^bSauSl;i&!J}OzErY??p8{N1ytML2eW5487K}rG1Tf1NY`TAe3CsMY z{?TKtK)S>NnB|rFW5M$d0n1DFN2n?PcaccUG0yxy1CIs{H8At@2n5kCy*=sA^sAiZ z8w7|ugA3$B`5;4|*7W}ug^vk9|&O`nkI`tz1Kp5bHRNj&nB&l~P?|7I6_#-;p)ip;^sf)l_T zm&|XU%l$JsNVH2Y?|c(xc_%hBl8yGBZ^BIP+{igS)`XcJ*Vs8d-h`RH%Y->T_L(r# zue;RmjH!ODi>cpT)BX4gs)aZo`N;mshyu_qy}mgn91nToSfo=v75ETvF9YWSd*U}p z;|$F5O$OF4J-=xtJO%Q^^8Tg3XMpE`%ksoFbH0DL3Gas-@h+46o#xK+UM-67=a3^# zL6pqjE4nD1?dxsATKk)@*8V2U^dnrPXqR5UlP1jcG63vy zJEJ@XX8T+K)-S#M-BqQst-rKk^aIYbHA-*v#pfLRV=%E!6bZ{i3oy`p6&>_l zlcwh}zaS3~?eejF2zhx)eerTBZ$!M5(A&3>2{XU5Cd}vFHesfp7+7>a@w6u;*6Vj& zpQa+x$MShG<+*9P{}R%PSq19LkHB|;{SD0gy#|43S4qoXNY4S@2uyjF&)bx4Q+3QD zOMOi1MpjrN4;1At2`m-cLz+z5d$5T#NFt_~Lo;lKpYp zlz%Ox6U+M42VOn|I)j^7{^r2L@lNTGf!QA3!(@(n{e4Y12J*!8yHO}H!MiOua9XG&-OLrfUk8X7jsFE*u9ewhiUK%N-Kw>!$ee3V`q zx&A0L;n9#MHjk%c8P4(-O!!I26K{lwY@dml&hpbtcoyV|sZvt@k|~|#=bz5%mu{a6 zvz+m}Ci}At`4LO|a|NPjf&Iayy^e74S9eVJufzSs950mL3>=K(swLhD91ncNl;5GU z0NUkac?0S4lJ@M7sl0C^o%k$-WPRsn%R6*^SZu{o|Dfpj~?Vc$+ZC zH?dj1y(yjfcQ#>;S7Nh#zA2sZ<4pJn%1>-A|8`S4<#(CzE#yx;)71Wr3bew5=;e<# zVcKKj6G)ZywTy9=_b}mm$e(zlDgVu5o#nTiFzq+-Ra5?p$2rR{Ghx~T;uMqoO;bAS zd)I{P18*PioZq`9%=Akx*qfU$+NJOJ5PJhl`*3oyp2}G}?~gFa(;g7VAfEEH7dgO_ z4P4fS`7H1<1M~jn6+pDh=Yjn|rpx_Wi>0)M{~jQ*01g4>{z5s(v43KK4~3wQ4crg- zE|f#2rvpzO039>ZCs978D18C&S>QQF`byxOmiqdH`R^yLi~chD_kH5lMd_D;Pxdd$ zpa0guf3;d=r*5j4$SqpyuT&z5$xxjH16+7`8dQG zI05)XOi_7qfw_KbZ zYM*n!8-at3=UoM!)4iy^e*n)6LVb;N)gAqh^2+?H18e(HMtXf{V>G9&4IaJv&z8Tfp_&S z!UKW1U)J78&j#lDKh(gJfG0v9W&NH9-W*fZemj6~L%)s~@^1j&fj$m5@M+*sjGqVt ze+4YxZ?M0A1Lk}~>fb%!n<%er-wGwre$aneo?5`PH@-%G4S?fK?b97ND5R)-1A&hr zzjB8BC}3~MOZ+5o8tUK6NS_b9%#{8ra4^~z#nSrw5U||ur#*TPnEN3SM*0`P(@_6> z1OEbCXez&ZNt73rxoOq&^8t=AmA?@%_Xmy`_qPY$6;t&51mNu`Y*QmW6PWuA`waX9 zFn`1#>$imRCjDFu?1}t?4f)-`DW>P21oo~C9W?aoYhdm_dmHjMfsbMQ^)k}`p?nPL zY^3ua%(>qzpI;qVzHeZAg#de+p4S3+pQ*pQ1JCJK&g{E}MuQg%H zZ+F4RO_=hZyWsC#@E^ePeP0E0?YTS z6)4h;H!|Ux!0k+!>D__TkgyNo3h@7lz|y{Pyzt*L$AtZXPns~FchLp^WWv0ke?22F;&LvynhW-G z!Szg-!NxAQl?(3Xf(N+Z6c;?k1y2DsxA$|Vbe4aW3*O^`-*mz6m@tE%n=tdc?1F!C z!D@L385iYCn=nOvOql64O_=EoTyR?xrhFF@rhJ?UGkqAaxjpQrbjs(t;3rI&_s?>{ z3r(2!uLd^j;}%mo@84y@lz-cVnSS1cnf`+bGyNA6X8Ju~^Yc^+85e`qTyUTZu4}@~ zFUo`&Z0mw8{N5|S?;4(L2}-mi=jP|-7mOGIlw!}dr>5uS+jA50GZT_Cva|5z)Swhg zF|i2=DcK3B8QDpR83`%**|~WMi3Q^<_`YjShCSb&65h0F<48-fLJ54d{x#YJd^a|C zyhZy)YeGsvX6AU@VnPWlsgr0%L1JEZ@+f;gN^3m5AS)v~F-4-hQRz9B%Sg29soBN=j~#q|x-qAuT&k%f*n_BTP?@bjm0{8@*#LLw>d+12oc@#Eb%a zc$21)T4OqpRyP(ENfFIhQ3FIqSqdELU>}!k&tX?XF|)Gs)6%n2rBa~%^6km_*wxdx zJtaY=WZB1R8knAyn2|ogZppJ}KoFVa+Vcx?vl2$6STYkw*%K1;@Ei;3i-_dx3<@DF zJSQW7?YT}7=EtR^=jM;sMP=Q!Y!j2&J$gb0ZH!So)(Kyp&(QD5PRVohKL!H(8UkAD zF&89T3R2j-pt3!Us^wD?ii(B1oy(bL&w`=S3t&`#L~eGbmXpjoA)#ZRHr+cUbm-AO zA;B@|+3v|1P=NyNtNn&;a6DFPIuw**3GC;r>=b(jelVb`CZnn3N#i+&r@1&^*%K7S%5wT?UJnD$A0dt#^;iMmDK|rI=&r%BLHHUbae6WsN$H%}qzq z9W74F;%IZ~NI{ma0cqJec~VRcEJw>Er`eN7>D?h8#Cu)zMq*E+a@-lXUC3xJH#c#wP_pMAwjbsjyiD66f;l}orGV}jAF0TzCZz7 zhorepwH`5yfg@{&LOTuiQJ8SR!NA};N}oTT?JWm9Z!4z9WKSR&HW?!XGpfAogtWx0 z6nq0gwk+F+*%f6Dd97h|gXL(y{H*LOM-9zpOuB=j&M98;ifxe;%ueJGf_pcfX6U_v z#wKFQS!7I{I$yJGh8%oiip+sV)9HZ^Hj>r_rbdF-#(dJKS$dv5GY7s%jzotw)blZo z4ya#xwl>*B1IKl5XV`z)8b!S)W3*AM^{~+guvzjkDd~A~d`fXt*QJqUnKivJ>TV9F z*irNBA{UYfk7+2QKF`qyq;aR=Pi3a4AA_uu<1UBZq0|lZL1WwuY27_(zEkFrnV36D zS2?quKvtg{$jZu^8YRH&IyONY{ir(4gCiZ&?({sAhGR=Nc?tN192Nj6aI{6YWfjm8 zbE2gcWJC(wXhK4wJuxXgAq7Q`iRsj?T|&d~#=J+LD#QIICSf!%f-~3=##1E5gxF5c zrL8+ODdz5Ui#F4= zTdp=|kcCO6ODo9LN*jxn4GKmRAgh?(z*Ix$j*%iMC`@X8Q9Edsm)WOh;bHk~I(DQs zS7$Wvh;(~K3hQO`jcyeZy2N!)C|dDB?YZ8I(;7w}3&!pFn0heCdTKgiE=q=}C=|l9 zz)@*DnmVT4qbW>IK2*YdcdEUpBD|aZC;f&tTyrqj)*g0z-LLivWiIfNRdPjC`S$W0uJY9N>7af#F*eVL$@H91i) z8^>*eF_@CG(YFbjYU`s%n?pg|D6>>XEyh@HVUmX>upO4qSYjm@!$Qx~qR)b~?ve{} zr_N$w^0Q^LX+=Xb8hYrc8Pvu;x~OhO-=GO}!w?nFc&JyEGsc9Ti*rH>Xj|?FxCiK>G32Pt>GM0RJVl|V@9b( z>yOdYJ1ajs(UM?y40trDZqE1+Otn>`p6^DYRCZ-p8 Gmj4fjVCtd( literal 0 HcmV?d00001 diff --git a/Me_Lua/h10/socket/core.so b/Me_Lua/h10/socket/core.so new file mode 100644 index 0000000000000000000000000000000000000000..c1aa8a232ac97944aa4165e70d756c74e4ac4b29 GIT binary patch literal 289771 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 Gmj4fjVCtd( literal 0 HcmV?d00001 diff --git a/Me_Lua/h10/socket/ftp.lua b/Me_Lua/h10/socket/ftp.lua new file mode 100644 index 0000000..ea1145b --- /dev/null +++ b/Me_Lua/h10/socket/ftp.lua @@ -0,0 +1,285 @@ +----------------------------------------------------------------------------- +-- FTP support for the Lua language +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local table = require("table") +local string = require("string") +local math = require("math") +local socket = require("socket") +local url = require("socket.url") +local tp = require("socket.tp") +local ltn12 = require("ltn12") +socket.ftp = {} +local _M = socket.ftp +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- timeout in seconds before the program gives up on a connection +_M.TIMEOUT = 60 +-- default port for ftp service +_M.PORT = 21 +-- this is the default anonymous password. used when no password is +-- provided in url. should be changed to your e-mail. +_M.USER = "ftp" +_M.PASSWORD = "anonymous@anonymous.org" + +----------------------------------------------------------------------------- +-- Low level FTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function _M.open(server, port, create) + local tp = socket.try(tp.connect(server, port or _M.PORT, _M.TIMEOUT, create)) + local f = base.setmetatable({ tp = tp }, metat) + -- make sure everything gets closed in an exception + f.try = socket.newtry(function() f:close() end) + return f +end + +function metat.__index:portconnect() + self.try(self.server:settimeout(_M.TIMEOUT)) + self.data = self.try(self.server:accept()) + self.try(self.data:settimeout(_M.TIMEOUT)) +end + +function metat.__index:pasvconnect() + self.data = self.try(socket.tcp()) + self.try(self.data:settimeout(_M.TIMEOUT)) + self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) +end + +function metat.__index:login(user, password) + self.try(self.tp:command("user", user or _M.USER)) + local code, reply = self.try(self.tp:check{"2..", 331}) + if code == 331 then + self.try(self.tp:command("pass", password or _M.PASSWORD)) + self.try(self.tp:check("2..")) + end + return 1 +end + +function metat.__index:pasv() + self.try(self.tp:command("pasv")) + local code, reply = self.try(self.tp:check("2..")) + local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" + local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) + self.try(a and b and c and d and p1 and p2, reply) + self.pasvt = { + ip = string.format("%d.%d.%d.%d", a, b, c, d), + port = p1*256 + p2 + } + if self.server then + self.server:close() + self.server = nil + end + return self.pasvt.ip, self.pasvt.port +end + +function metat.__index:port(ip, port) + self.pasvt = nil + if not ip then + ip, port = self.try(self.tp:getcontrol():getsockname()) + self.server = self.try(socket.bind(ip, 0)) + ip, port = self.try(self.server:getsockname()) + self.try(self.server:settimeout(_M.TIMEOUT)) + end + local pl = math.mod(port, 256) + local ph = (port - pl)/256 + local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") + self.try(self.tp:command("port", arg)) + self.try(self.tp:check("2..")) + return 1 +end + +function metat.__index:send(sendt) + self.try(self.pasvt or self.server, "need port or pasv first") + -- if there is a pasvt table, we already sent a PASV command + -- we just get the data connection into self.data + if self.pasvt then self:pasvconnect() end + -- get the transfer argument and command + local argument = sendt.argument or + url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) + if argument == "" then argument = nil end + local command = sendt.command or "stor" + -- send the transfer command and check the reply + self.try(self.tp:command(command, argument)) + local code, reply = self.try(self.tp:check{"2..", "1.."}) + -- if there is not a a pasvt table, then there is a server + -- and we already sent a PORT command + if not self.pasvt then self:portconnect() end + -- get the sink, source and step for the transfer + local step = sendt.step or ltn12.pump.step + local readt = {self.tp.c} + local checkstep = function(src, snk) + -- check status in control connection while downloading + local readyt = socket.select(readt, nil, 0) + if readyt[tp] then code = self.try(self.tp:check("2..")) end + return step(src, snk) + end + local sink = socket.sink("close-when-done", self.data) + -- transfer all data and check error + self.try(ltn12.pump.all(sendt.source, sink, checkstep)) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + -- done with data connection + self.data:close() + -- find out how many bytes were sent + local sent = socket.skip(1, self.data:getstats()) + self.data = nil + return sent +end + +function metat.__index:receive(recvt) + self.try(self.pasvt or self.server, "need port or pasv first") + if self.pasvt then self:pasvconnect() end + local argument = recvt.argument or + url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) + if argument == "" then argument = nil end + local command = recvt.command or "retr" + self.try(self.tp:command(command, argument)) + local code,reply = self.try(self.tp:check{"1..", "2.."}) + if (code >= 200) and (code <= 299) then + recvt.sink(reply) + return 1 + end + if not self.pasvt then self:portconnect() end + local source = socket.source("until-closed", self.data) + local step = recvt.step or ltn12.pump.step + self.try(ltn12.pump.all(source, recvt.sink, step)) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + self.data:close() + self.data = nil + return 1 +end + +function metat.__index:cwd(dir) + self.try(self.tp:command("cwd", dir)) + self.try(self.tp:check(250)) + return 1 +end + +function metat.__index:type(type) + self.try(self.tp:command("type", type)) + self.try(self.tp:check(200)) + return 1 +end + +function metat.__index:greet() + local code = self.try(self.tp:check{"1..", "2.."}) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + return 1 +end + +function metat.__index:quit() + self.try(self.tp:command("quit")) + self.try(self.tp:check("2..")) + return 1 +end + +function metat.__index:close() + if self.data then self.data:close() end + if self.server then self.server:close() end + return self.tp:close() +end + +----------------------------------------------------------------------------- +-- High level FTP API +----------------------------------------------------------------------------- +local function override(t) + if t.url then + local u = url.parse(t.url) + for i,v in base.pairs(t) do + u[i] = v + end + return u + else return t end +end + +local function tput(putt) + putt = override(putt) + socket.try(putt.host, "missing hostname") + local f = _M.open(putt.host, putt.port, putt.create) + f:greet() + f:login(putt.user, putt.password) + if putt.type then f:type(putt.type) end + f:pasv() + local sent = f:send(putt) + f:quit() + f:close() + return sent +end + +local default = { + path = "/", + scheme = "ftp" +} + +local function parse(u) + local t = socket.try(url.parse(u, default)) + socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") + socket.try(t.host, "missing hostname") + local pat = "^type=(.)$" + if t.params then + t.type = socket.skip(2, string.find(t.params, pat)) + socket.try(t.type == "a" or t.type == "i", + "invalid type '" .. t.type .. "'") + end + return t +end + +local function sput(u, body) + local putt = parse(u) + putt.source = ltn12.source.string(body) + return tput(putt) +end + +_M.put = socket.protect(function(putt, body) + if base.type(putt) == "string" then return sput(putt, body) + else return tput(putt) end +end) + +local function tget(gett) + gett = override(gett) + socket.try(gett.host, "missing hostname") + local f = _M.open(gett.host, gett.port, gett.create) + f:greet() + f:login(gett.user, gett.password) + if gett.type then f:type(gett.type) end + f:pasv() + f:receive(gett) + f:quit() + return f:close() +end + +local function sget(u) + local gett = parse(u) + local t = {} + gett.sink = ltn12.sink.table(t) + tget(gett) + return table.concat(t) +end + +_M.command = socket.protect(function(cmdt) + cmdt = override(cmdt) + socket.try(cmdt.host, "missing hostname") + socket.try(cmdt.command, "missing command") + local f = open(cmdt.host, cmdt.port, cmdt.create) + f:greet() + f:login(cmdt.user, cmdt.password) + f.try(f.tp:command(cmdt.command, cmdt.argument)) + if cmdt.check then f.try(f.tp:check(cmdt.check)) end + f:quit() + return f:close() +end) + +_M.get = socket.protect(function(gett) + if base.type(gett) == "string" then return sget(gett) + else return tget(gett) end +end) + +return _M \ No newline at end of file diff --git a/Me_Lua/h10/socket/headers.lua b/Me_Lua/h10/socket/headers.lua new file mode 100644 index 0000000..1eb8223 --- /dev/null +++ b/Me_Lua/h10/socket/headers.lua @@ -0,0 +1,104 @@ +----------------------------------------------------------------------------- +-- Canonic header field capitalization +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- +local socket = require("socket") +socket.headers = {} +local _M = socket.headers + +_M.canonic = { + ["accept"] = "Accept", + ["accept-charset"] = "Accept-Charset", + ["accept-encoding"] = "Accept-Encoding", + ["accept-language"] = "Accept-Language", + ["accept-ranges"] = "Accept-Ranges", + ["action"] = "Action", + ["alternate-recipient"] = "Alternate-Recipient", + ["age"] = "Age", + ["allow"] = "Allow", + ["arrival-date"] = "Arrival-Date", + ["authorization"] = "Authorization", + ["bcc"] = "Bcc", + ["cache-control"] = "Cache-Control", + ["cc"] = "Cc", + ["comments"] = "Comments", + ["connection"] = "Connection", + ["content-description"] = "Content-Description", + ["content-disposition"] = "Content-Disposition", + ["content-encoding"] = "Content-Encoding", + ["content-id"] = "Content-ID", + ["content-language"] = "Content-Language", + ["content-length"] = "Content-Length", + ["content-location"] = "Content-Location", + ["content-md5"] = "Content-MD5", + ["content-range"] = "Content-Range", + ["content-transfer-encoding"] = "Content-Transfer-Encoding", + ["content-type"] = "Content-Type", + ["cookie"] = "Cookie", + ["date"] = "Date", + ["diagnostic-code"] = "Diagnostic-Code", + ["dsn-gateway"] = "DSN-Gateway", + ["etag"] = "ETag", + ["expect"] = "Expect", + ["expires"] = "Expires", + ["final-log-id"] = "Final-Log-ID", + ["final-recipient"] = "Final-Recipient", + ["from"] = "From", + ["host"] = "Host", + ["if-match"] = "If-Match", + ["if-modified-since"] = "If-Modified-Since", + ["if-none-match"] = "If-None-Match", + ["if-range"] = "If-Range", + ["if-unmodified-since"] = "If-Unmodified-Since", + ["in-reply-to"] = "In-Reply-To", + ["keywords"] = "Keywords", + ["last-attempt-date"] = "Last-Attempt-Date", + ["last-modified"] = "Last-Modified", + ["location"] = "Location", + ["max-forwards"] = "Max-Forwards", + ["message-id"] = "Message-ID", + ["mime-version"] = "MIME-Version", + ["original-envelope-id"] = "Original-Envelope-ID", + ["original-recipient"] = "Original-Recipient", + ["pragma"] = "Pragma", + ["proxy-authenticate"] = "Proxy-Authenticate", + ["proxy-authorization"] = "Proxy-Authorization", + ["range"] = "Range", + ["received"] = "Received", + ["received-from-mta"] = "Received-From-MTA", + ["references"] = "References", + ["referer"] = "Referer", + ["remote-mta"] = "Remote-MTA", + ["reply-to"] = "Reply-To", + ["reporting-mta"] = "Reporting-MTA", + ["resent-bcc"] = "Resent-Bcc", + ["resent-cc"] = "Resent-Cc", + ["resent-date"] = "Resent-Date", + ["resent-from"] = "Resent-From", + ["resent-message-id"] = "Resent-Message-ID", + ["resent-reply-to"] = "Resent-Reply-To", + ["resent-sender"] = "Resent-Sender", + ["resent-to"] = "Resent-To", + ["retry-after"] = "Retry-After", + ["return-path"] = "Return-Path", + ["sender"] = "Sender", + ["server"] = "Server", + ["smtp-remote-recipient"] = "SMTP-Remote-Recipient", + ["status"] = "Status", + ["subject"] = "Subject", + ["te"] = "TE", + ["to"] = "To", + ["trailer"] = "Trailer", + ["transfer-encoding"] = "Transfer-Encoding", + ["upgrade"] = "Upgrade", + ["user-agent"] = "User-Agent", + ["vary"] = "Vary", + ["via"] = "Via", + ["warning"] = "Warning", + ["will-retry-until"] = "Will-Retry-Until", + ["www-authenticate"] = "WWW-Authenticate", + ["x-mailer"] = "X-Mailer", +} + +return _M \ No newline at end of file diff --git a/Me_Lua/h10/socket/http.lua b/Me_Lua/h10/socket/http.lua new file mode 100644 index 0000000..4f8c1c8 --- /dev/null +++ b/Me_Lua/h10/socket/http.lua @@ -0,0 +1,356 @@ +----------------------------------------------------------------------------- +-- HTTP/1.1 client support for the Lua language. +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +------------------------------------------------------------------------------- +local socket = require("socket") +local url = require("socket.url") +local ltn12 = require("ltn12") +local mime = require("mime") +local string = require("string") +local headers = require("socket.headers") +local base = _G +local table = require("table") +socket.http = {} +local _M = socket.http + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- connection timeout in seconds +_M.TIMEOUT = 60 +-- default port for document retrieval +_M.PORT = 80 +-- user agent field sent in request +_M.USERAGENT = socket._VERSION + +----------------------------------------------------------------------------- +-- Reads MIME headers from a connection, unfolding where needed +----------------------------------------------------------------------------- +local function receiveheaders(sock, headers) + local line, name, value, err + headers = headers or {} + -- get first line + line, err = sock:receive() + if err then return nil, err end + -- headers go until a blank line is found + while line ~= "" do + -- get field-name and value + name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) + if not (name and value) then return nil, "malformed reponse headers" end + name = string.lower(name) + -- get next line (value might be folded) + line, err = sock:receive() + if err then return nil, err end + -- unfold any folded values + while string.find(line, "^%s") do + value = value .. line + line = sock:receive() + if err then return nil, err end + end + -- save pair in table + if headers[name] then headers[name] = headers[name] .. ", " .. value + else headers[name] = value end + end + return headers +end + +----------------------------------------------------------------------------- +-- Extra sources and sinks +----------------------------------------------------------------------------- +socket.sourcet["http-chunked"] = function(sock, headers) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + -- get chunk size, skip extention + local line, err = sock:receive() + if err then return nil, err end + local size = base.tonumber(string.gsub(line, ";.*", ""), 16) + if not size then return nil, "invalid chunk size" end + -- was it the last chunk? + if size > 0 then + -- if not, get chunk and skip terminating CRLF + local chunk, err, part = sock:receive(size) + if chunk then sock:receive() end + return chunk, err + else + -- if it was, read trailers into headers table + headers, err = receiveheaders(sock, headers) + if not headers then return nil, err end + end + end + }) +end + +socket.sinkt["http-chunked"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if not chunk then return sock:send("0\r\n\r\n") end + local size = string.format("%X\r\n", string.len(chunk)) + return sock:send(size .. chunk .. "\r\n") + end + }) +end + +----------------------------------------------------------------------------- +-- Low level HTTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function _M.open(host, port, create) + -- create socket with user connect function, or with default + local c = socket.try((create or socket.tcp)()) + local h = base.setmetatable({ c = c }, metat) + -- create finalized try + h.try = socket.newtry(function() h:close() end) + -- set timeout before connecting + h.try(c:settimeout(_M.TIMEOUT)) + h.try(c:connect(host, port or _M.PORT)) + -- here everything worked + return h +end + +function metat.__index:sendrequestline(method, uri) + local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) + return self.try(self.c:send(reqline)) +end + +function metat.__index:sendheaders(tosend) + local canonic = headers.canonic + local h = "\r\n" + for f, v in base.pairs(tosend) do + h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h + end + self.try(self.c:send(h)) + return 1 +end + +function metat.__index:sendbody(headers, source, step) + source = source or ltn12.source.empty() + step = step or ltn12.pump.step + -- if we don't know the size in advance, send chunked and hope for the best + local mode = "http-chunked" + if headers["content-length"] then mode = "keep-open" end + return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) +end + +function metat.__index:receivestatusline() + local status = self.try(self.c:receive(5)) + -- identify HTTP/0.9 responses, which do not contain a status line + -- this is just a heuristic, but is what the RFC recommends + if status ~= "HTTP/" then return nil, status end + -- otherwise proceed reading a status line + status = self.try(self.c:receive("*l", status)) + local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) + return self.try(base.tonumber(code), status) +end + +function metat.__index:receiveheaders() + return self.try(receiveheaders(self.c)) +end + +function metat.__index:receivebody(headers, sink, step) + sink = sink or ltn12.sink.null() + step = step or ltn12.pump.step + local length = base.tonumber(headers["content-length"]) + local t = headers["transfer-encoding"] -- shortcut + local mode = "default" -- connection close + if t and t ~= "identity" then mode = "http-chunked" + elseif base.tonumber(headers["content-length"]) then mode = "by-length" end + return self.try(ltn12.pump.all(socket.source(mode, self.c, length), + sink, step)) +end + +function metat.__index:receive09body(status, sink, step) + local source = ltn12.source.rewind(socket.source("until-closed", self.c)) + source(status) + return self.try(ltn12.pump.all(source, sink, step)) +end + +function metat.__index:close() + return self.c:close() +end + +----------------------------------------------------------------------------- +-- High level HTTP API +----------------------------------------------------------------------------- +local function adjusturi(reqt) + local u = reqt + -- if there is a proxy, we need the full url. otherwise, just a part. + if not reqt.proxy and not _M.PROXY then + u = { + path = socket.try(reqt.path, "invalid path 'nil'"), + params = reqt.params, + query = reqt.query, + fragment = reqt.fragment + } + end + return url.build(u) +end + +local function adjustproxy(reqt) + local proxy = reqt.proxy or _M.PROXY + if proxy then + proxy = url.parse(proxy) + return proxy.host, proxy.port or 3128 + else + return reqt.host, reqt.port + end +end + +local function adjustheaders(reqt) + -- default headers + local host = reqt.host + if reqt.port then host = host .. ":" .. reqt.port end + local lower = { + ["user-agent"] = _M.USERAGENT, + ["host"] = host, + ["connection"] = "close, TE", + ["te"] = "trailers" + } + -- if we have authentication information, pass it along + if reqt.user and reqt.password then + lower["authorization"] = + "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) + end + -- override with user headers + for i,v in base.pairs(reqt.headers or lower) do + lower[string.lower(i)] = v + end + return lower +end + +-- default url parts +local default = { + host = "", + port = _M.PORT, + path ="/", + scheme = "http" +} + +local function adjustrequest(reqt) + -- parse url if provided + local nreqt = reqt.url and url.parse(reqt.url, default) or {} + -- explicit components override url + for i,v in base.pairs(reqt) do nreqt[i] = v end + if nreqt.port == "" then nreqt.port = 80 end + socket.try(nreqt.host and nreqt.host ~= "", + "invalid host '" .. base.tostring(nreqt.host) .. "'") + -- compute uri if user hasn't overriden + nreqt.uri = reqt.uri or adjusturi(nreqt) + -- ajust host and port if there is a proxy + nreqt.host, nreqt.port = adjustproxy(nreqt) + -- adjust headers in request + nreqt.headers = adjustheaders(nreqt) + return nreqt +end + +local function shouldredirect(reqt, code, headers) + return headers.location and + string.gsub(headers.location, "%s", "") ~= "" and + (reqt.redirect ~= false) and + (code == 301 or code == 302 or code == 303 or code == 307) and + (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") + and (not reqt.nredirects or reqt.nredirects < 5) +end + +local function shouldreceivebody(reqt, code) + if reqt.method == "HEAD" then return nil end + if code == 204 or code == 304 then return nil end + if code >= 100 and code < 200 then return nil end + return 1 +end + +-- forward declarations +local trequest, tredirect + +--[[local]] function tredirect(reqt, location) + local result, code, headers, status = trequest { + -- the RFC says the redirect URL has to be absolute, but some + -- servers do not respect that + url = url.absolute(reqt.url, location), + source = reqt.source, + sink = reqt.sink, + headers = reqt.headers, + proxy = reqt.proxy, + nredirects = (reqt.nredirects or 0) + 1, + create = reqt.create + } + -- pass location header back as a hint we redirected + headers = headers or {} + headers.location = headers.location or location + return result, code, headers, status +end + +--[[local]] function trequest(reqt) + -- we loop until we get what we want, or + -- until we are sure there is no way to get it + local nreqt = adjustrequest(reqt) + local h = _M.open(nreqt.host, nreqt.port, nreqt.create) + -- send request line and headers + h:sendrequestline(nreqt.method, nreqt.uri) + h:sendheaders(nreqt.headers) + -- if there is a body, send it + if nreqt.source then + h:sendbody(nreqt.headers, nreqt.source, nreqt.step) + end + local code, status = h:receivestatusline() + -- if it is an HTTP/0.9 server, simply get the body and we are done + if not code then + h:receive09body(status, nreqt.sink, nreqt.step) + return 1, 200 + end + local headers + -- ignore any 100-continue messages + while code == 100 do + headers = h:receiveheaders() + code, status = h:receivestatusline() + end + headers = h:receiveheaders() + -- at this point we should have a honest reply from the server + -- we can't redirect if we already used the source, so we report the error + if shouldredirect(nreqt, code, headers) and not nreqt.source then + h:close() + return tredirect(reqt, headers.location) + end + -- here we are finally done + if shouldreceivebody(nreqt, code) then + h:receivebody(headers, nreqt.sink, nreqt.step) + end + h:close() + return 1, code, headers, status +end + +local function srequest(u, b) + local t = {} + local reqt = { + url = u, + sink = ltn12.sink.table(t) + } + if b then + reqt.source = ltn12.source.string(b) + reqt.headers = { + ["content-length"] = string.len(b), + ["content-type"] = "application/x-www-form-urlencoded" + } + reqt.method = "POST" + end + local code, headers, status = socket.skip(1, trequest(reqt)) + return table.concat(t), code, headers, status +end + +_M.request = socket.protect(function(reqt, body) + if base.type(reqt) == "string" then return srequest(reqt, body) + else return trequest(reqt) end +end) + +return _M \ No newline at end of file diff --git a/Me_Lua/h10/socket/smtp.lua b/Me_Lua/h10/socket/smtp.lua new file mode 100644 index 0000000..b113d00 --- /dev/null +++ b/Me_Lua/h10/socket/smtp.lua @@ -0,0 +1,256 @@ +----------------------------------------------------------------------------- +-- SMTP client support for the Lua language. +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local coroutine = require("coroutine") +local string = require("string") +local math = require("math") +local os = require("os") +local socket = require("socket") +local tp = require("socket.tp") +local ltn12 = require("ltn12") +local headers = require("socket.headers") +local mime = require("mime") + +socket.smtp = {} +local _M = socket.smtp + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- timeout for connection +_M.TIMEOUT = 60 +-- default server used to send e-mails +_M.SERVER = "localhost" +-- default port +_M.PORT = 25 +-- domain used in HELO command and default sendmail +-- If we are under a CGI, try to get from environment +_M.DOMAIN = os.getenv("SERVER_NAME") or "localhost" +-- default time zone (means we don't know) +_M.ZONE = "-0000" + +--------------------------------------------------------------------------- +-- Low level SMTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function metat.__index:greet(domain) + self.try(self.tp:check("2..")) + self.try(self.tp:command("EHLO", domain or _M.DOMAIN)) + return socket.skip(1, self.try(self.tp:check("2.."))) +end + +function metat.__index:mail(from) + self.try(self.tp:command("MAIL", "FROM:" .. from)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:rcpt(to) + self.try(self.tp:command("RCPT", "TO:" .. to)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:data(src, step) + self.try(self.tp:command("DATA")) + self.try(self.tp:check("3..")) + self.try(self.tp:source(src, step)) + self.try(self.tp:send("\r\n.\r\n")) + return self.try(self.tp:check("2..")) +end + +function metat.__index:quit() + self.try(self.tp:command("QUIT")) + return self.try(self.tp:check("2..")) +end + +function metat.__index:close() + return self.tp:close() +end + +function metat.__index:login(user, password) + self.try(self.tp:command("AUTH", "LOGIN")) + self.try(self.tp:check("3..")) + self.try(self.tp:send(mime.b64(user) .. "\r\n")) + self.try(self.tp:check("3..")) + self.try(self.tp:send(mime.b64(password) .. "\r\n")) + return self.try(self.tp:check("2..")) +end + +function metat.__index:plain(user, password) + local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password) + self.try(self.tp:command("AUTH", auth)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:auth(user, password, ext) + if not user or not password then return 1 end + if string.find(ext, "AUTH[^\n]+LOGIN") then + return self:login(user, password) + elseif string.find(ext, "AUTH[^\n]+PLAIN") then + return self:plain(user, password) + else + self.try(nil, "authentication not supported") + end +end + +-- send message or throw an exception +function metat.__index:send(mailt) + self:mail(mailt.from) + if base.type(mailt.rcpt) == "table" then + for i,v in base.ipairs(mailt.rcpt) do + self:rcpt(v) + end + else + self:rcpt(mailt.rcpt) + end + self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step) +end + +function _M.open(server, port, create) + local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT, + _M.TIMEOUT, create)) + local s = base.setmetatable({tp = tp}, metat) + -- make sure tp is closed if we get an exception + s.try = socket.newtry(function() + s:close() + end) + return s +end + +-- convert headers to lowercase +local function lower_headers(headers) + local lower = {} + for i,v in base.pairs(headers or lower) do + lower[string.lower(i)] = v + end + return lower +end + +--------------------------------------------------------------------------- +-- Multipart message source +----------------------------------------------------------------------------- +-- returns a hopefully unique mime boundary +local seqno = 0 +local function newboundary() + seqno = seqno + 1 + return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'), + math.random(0, 99999), seqno) +end + +-- send_message forward declaration +local send_message + +-- yield the headers all at once, it's faster +local function send_headers(tosend) + local canonic = headers.canonic + local h = "\r\n" + for f,v in base.pairs(tosend) do + h = (canonic[f] or f) .. ': ' .. v .. "\r\n" .. h + end + coroutine.yield(h) +end + +-- yield multipart message body from a multipart message table +local function send_multipart(mesgt) + -- make sure we have our boundary and send headers + local bd = newboundary() + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or 'multipart/mixed' + headers['content-type'] = headers['content-type'] .. + '; boundary="' .. bd .. '"' + send_headers(headers) + -- send preamble + if mesgt.body.preamble then + coroutine.yield(mesgt.body.preamble) + coroutine.yield("\r\n") + end + -- send each part separated by a boundary + for i, m in base.ipairs(mesgt.body) do + coroutine.yield("\r\n--" .. bd .. "\r\n") + send_message(m) + end + -- send last boundary + coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") + -- send epilogue + if mesgt.body.epilogue then + coroutine.yield(mesgt.body.epilogue) + coroutine.yield("\r\n") + end +end + +-- yield message body from a source +local function send_source(mesgt) + -- make sure we have a content-type + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or + 'text/plain; charset="iso-8859-1"' + send_headers(headers) + -- send body from source + while true do + local chunk, err = mesgt.body() + if err then coroutine.yield(nil, err) + elseif chunk then coroutine.yield(chunk) + else break end + end +end + +-- yield message body from a string +local function send_string(mesgt) + -- make sure we have a content-type + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or + 'text/plain; charset="iso-8859-1"' + send_headers(headers) + -- send body from string + coroutine.yield(mesgt.body) +end + +-- message source +function send_message(mesgt) + if base.type(mesgt.body) == "table" then send_multipart(mesgt) + elseif base.type(mesgt.body) == "function" then send_source(mesgt) + else send_string(mesgt) end +end + +-- set defaul headers +local function adjust_headers(mesgt) + local lower = lower_headers(mesgt.headers) + lower["date"] = lower["date"] or + os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE) + lower["x-mailer"] = lower["x-mailer"] or socket._VERSION + -- this can't be overriden + lower["mime-version"] = "1.0" + return lower +end + +function _M.message(mesgt) + mesgt.headers = adjust_headers(mesgt) + -- create and return message source + local co = coroutine.create(function() send_message(mesgt) end) + return function() + local ret, a, b = coroutine.resume(co) + if ret then return a, b + else return nil, a end + end +end + +--------------------------------------------------------------------------- +-- High level SMTP API +----------------------------------------------------------------------------- +_M.send = socket.protect(function(mailt) + local s = _M.open(mailt.server, mailt.port, mailt.create) + local ext = s:greet(mailt.domain) + s:auth(mailt.user, mailt.password, ext) + s:send(mailt) + s:quit() + return s:close() +end) + +return _M \ No newline at end of file diff --git a/Me_Lua/h10/socket/tp.lua b/Me_Lua/h10/socket/tp.lua new file mode 100644 index 0000000..cbeff56 --- /dev/null +++ b/Me_Lua/h10/socket/tp.lua @@ -0,0 +1,126 @@ +----------------------------------------------------------------------------- +-- Unified SMTP/FTP subsystem +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local string = require("string") +local socket = require("socket") +local ltn12 = require("ltn12") + +socket.tp = {} +local _M = socket.tp + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +_M.TIMEOUT = 60 + +----------------------------------------------------------------------------- +-- Implementation +----------------------------------------------------------------------------- +-- gets server reply (works for SMTP and FTP) +local function get_reply(c) + local code, current, sep + local line, err = c:receive() + local reply = line + if err then return nil, err end + code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) + if not code then return nil, "invalid server reply" end + if sep == "-" then -- reply is multiline + repeat + line, err = c:receive() + if err then return nil, err end + current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) + reply = reply .. "\n" .. line + -- reply ends with same code + until code == current and sep == " " + end + return code, reply +end + +-- metatable for sock object +local metat = { __index = {} } + +function metat.__index:check(ok) + local code, reply = get_reply(self.c) + if not code then return nil, reply end + if base.type(ok) ~= "function" then + if base.type(ok) == "table" then + for i, v in base.ipairs(ok) do + if string.find(code, v) then + return base.tonumber(code), reply + end + end + return nil, reply + else + if string.find(code, ok) then return base.tonumber(code), reply + else return nil, reply end + end + else return ok(base.tonumber(code), reply) end +end + +function metat.__index:command(cmd, arg) + cmd = string.upper(cmd) + if arg then + return self.c:send(cmd .. " " .. arg.. "\r\n") + else + return self.c:send(cmd .. "\r\n") + end +end + +function metat.__index:sink(snk, pat) + local chunk, err = c:receive(pat) + return snk(chunk, err) +end + +function metat.__index:send(data) + return self.c:send(data) +end + +function metat.__index:receive(pat) + return self.c:receive(pat) +end + +function metat.__index:getfd() + return self.c:getfd() +end + +function metat.__index:dirty() + return self.c:dirty() +end + +function metat.__index:getcontrol() + return self.c +end + +function metat.__index:source(source, step) + local sink = socket.sink("keep-open", self.c) + local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) + return ret, err +end + +-- closes the underlying c +function metat.__index:close() + self.c:close() + return 1 +end + +-- connect with server and return c object +function _M.connect(host, port, timeout, create) + local c, e = (create or socket.tcp)() + if not c then return nil, e end + c:settimeout(timeout or _M.TIMEOUT) + local r, e = c:connect(host, port) + if not r then + c:close() + return nil, e + end + return base.setmetatable({c = c}, metat) +end + +return _M \ No newline at end of file diff --git a/Me_Lua/h10/socket/url.lua b/Me_Lua/h10/socket/url.lua new file mode 100644 index 0000000..92ba7fd --- /dev/null +++ b/Me_Lua/h10/socket/url.lua @@ -0,0 +1,307 @@ +----------------------------------------------------------------------------- +-- URI parsing, composition and relative URL resolution +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module +----------------------------------------------------------------------------- +local string = require("string") +local base = _G +local table = require("table") +local socket = require("socket") + +socket.url = {} +local _M = socket.url + +----------------------------------------------------------------------------- +-- Module version +----------------------------------------------------------------------------- +_M._VERSION = "URL 1.0.3" + +----------------------------------------------------------------------------- +-- Encodes a string into its escaped hexadecimal representation +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +function _M.escape(s) + return (string.gsub(s, "([^A-Za-z0-9_])", function(c) + return string.format("%%%02x", string.byte(c)) + end)) +end + +----------------------------------------------------------------------------- +-- Protects a path segment, to prevent it from interfering with the +-- url parsing. +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +local function make_set(t) + local s = {} + for i,v in base.ipairs(t) do + s[t[i]] = 1 + end + return s +end + +-- these are allowed withing a path segment, along with alphanum +-- other characters must be escaped +local segment_set = make_set { + "-", "_", ".", "!", "~", "*", "'", "(", + ")", ":", "@", "&", "=", "+", "$", ",", +} + +local function protect_segment(s) + return string.gsub(s, "([^A-Za-z0-9_])", function (c) + if segment_set[c] then return c + else return string.format("%%%02x", string.byte(c)) end + end) +end + +----------------------------------------------------------------------------- +-- Encodes a string into its escaped hexadecimal representation +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +function _M.unescape(s) + return (string.gsub(s, "%%(%x%x)", function(hex) + return string.char(base.tonumber(hex, 16)) + end)) +end + +----------------------------------------------------------------------------- +-- Builds a path from a base path and a relative path +-- Input +-- base_path +-- relative_path +-- Returns +-- corresponding absolute path +----------------------------------------------------------------------------- +local function absolute_path(base_path, relative_path) + if string.sub(relative_path, 1, 1) == "/" then return relative_path end + local path = string.gsub(base_path, "[^/]*$", "") + path = path .. relative_path + path = string.gsub(path, "([^/]*%./)", function (s) + if s ~= "./" then return s else return "" end + end) + path = string.gsub(path, "/%.$", "/") + local reduced + while reduced ~= path do + reduced = path + path = string.gsub(reduced, "([^/]*/%.%./)", function (s) + if s ~= "../../" then return "" else return s end + end) + end + path = string.gsub(reduced, "([^/]*/%.%.)$", function (s) + if s ~= "../.." then return "" else return s end + end) + return path +end + +----------------------------------------------------------------------------- +-- Parses a url and returns a table with all its parts according to RFC 2396 +-- The following grammar describes the names given to the URL parts +-- ::= :///;?# +-- ::= @: +-- ::= [:] +-- :: = {/} +-- Input +-- url: uniform resource locator of request +-- default: table with default values for each field +-- Returns +-- table with the following fields, where RFC naming conventions have +-- been preserved: +-- scheme, authority, userinfo, user, password, host, port, +-- path, params, query, fragment +-- Obs: +-- the leading '/' in {/} is considered part of +----------------------------------------------------------------------------- +function _M.parse(url, default) + -- initialize default parameters + local parsed = {} + for i,v in base.pairs(default or parsed) do parsed[i] = v end + -- empty url is parsed to nil + if not url or url == "" then return nil, "invalid url" end + -- remove whitespace + -- url = string.gsub(url, "%s", "") + -- get fragment + url = string.gsub(url, "#(.*)$", function(f) + parsed.fragment = f + return "" + end) + -- get scheme + url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", + function(s) parsed.scheme = s; return "" end) + -- get authority + url = string.gsub(url, "^//([^/]*)", function(n) + parsed.authority = n + return "" + end) + -- get query string + url = string.gsub(url, "%?(.*)", function(q) + parsed.query = q + return "" + end) + -- get params + url = string.gsub(url, "%;(.*)", function(p) + parsed.params = p + return "" + end) + -- path is whatever was left + if url ~= "" then parsed.path = url end + local authority = parsed.authority + if not authority then return parsed end + authority = string.gsub(authority,"^([^@]*)@", + function(u) parsed.userinfo = u; return "" end) + authority = string.gsub(authority, ":([^:%]]*)$", + function(p) parsed.port = p; return "" end) + if authority ~= "" then + -- IPv6? + parsed.host = string.match(authority, "^%[(.+)%]$") or authority + end + local userinfo = parsed.userinfo + if not userinfo then return parsed end + userinfo = string.gsub(userinfo, ":([^:]*)$", + function(p) parsed.password = p; return "" end) + parsed.user = userinfo + return parsed +end + +----------------------------------------------------------------------------- +-- Rebuilds a parsed URL from its components. +-- Components are protected if any reserved or unallowed characters are found +-- Input +-- parsed: parsed URL, as returned by parse +-- Returns +-- a stringing with the corresponding URL +----------------------------------------------------------------------------- +function _M.build(parsed) + local ppath = _M.parse_path(parsed.path or "") + local url = _M.build_path(ppath) + if parsed.params then url = url .. ";" .. parsed.params end + if parsed.query then url = url .. "?" .. parsed.query end + local authority = parsed.authority + if parsed.host then + authority = parsed.host + if string.find(authority, ":") then -- IPv6? + authority = "[" .. authority .. "]" + end + if parsed.port then authority = authority .. ":" .. parsed.port end + local userinfo = parsed.userinfo + if parsed.user then + userinfo = parsed.user + if parsed.password then + userinfo = userinfo .. ":" .. parsed.password + end + end + if userinfo then authority = userinfo .. "@" .. authority end + end + if authority then url = "//" .. authority .. url end + if parsed.scheme then url = parsed.scheme .. ":" .. url end + if parsed.fragment then url = url .. "#" .. parsed.fragment end + -- url = string.gsub(url, "%s", "") + return url +end + +----------------------------------------------------------------------------- +-- Builds a absolute URL from a base and a relative URL according to RFC 2396 +-- Input +-- base_url +-- relative_url +-- Returns +-- corresponding absolute url +----------------------------------------------------------------------------- +function _M.absolute(base_url, relative_url) + if base.type(base_url) == "table" then + base_parsed = base_url + base_url = _M.build(base_parsed) + else + base_parsed = _M.parse(base_url) + end + local relative_parsed = _M.parse(relative_url) + if not base_parsed then return relative_url + elseif not relative_parsed then return base_url + elseif relative_parsed.scheme then return relative_url + else + relative_parsed.scheme = base_parsed.scheme + if not relative_parsed.authority then + relative_parsed.authority = base_parsed.authority + if not relative_parsed.path then + relative_parsed.path = base_parsed.path + if not relative_parsed.params then + relative_parsed.params = base_parsed.params + if not relative_parsed.query then + relative_parsed.query = base_parsed.query + end + end + else + relative_parsed.path = absolute_path(base_parsed.path or "", + relative_parsed.path) + end + end + return _M.build(relative_parsed) + end +end + +----------------------------------------------------------------------------- +-- Breaks a path into its segments, unescaping the segments +-- Input +-- path +-- Returns +-- segment: a table with one entry per segment +----------------------------------------------------------------------------- +function _M.parse_path(path) + local parsed = {} + path = path or "" + --path = string.gsub(path, "%s", "") + string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) + for i = 1, #parsed do + parsed[i] = _M.unescape(parsed[i]) + end + if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end + if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end + return parsed +end + +----------------------------------------------------------------------------- +-- Builds a path component from its segments, escaping protected characters. +-- Input +-- parsed: path segments +-- unsafe: if true, segments are not protected before path is built +-- Returns +-- path: corresponding path stringing +----------------------------------------------------------------------------- +function _M.build_path(parsed, unsafe) + local path = "" + local n = #parsed + if unsafe then + for i = 1, n-1 do + path = path .. parsed[i] + path = path .. "/" + end + if n > 0 then + path = path .. parsed[n] + if parsed.is_directory then path = path .. "/" end + end + else + for i = 1, n-1 do + path = path .. protect_segment(parsed[i]) + path = path .. "/" + end + if n > 0 then + path = path .. protect_segment(parsed[n]) + if parsed.is_directory then path = path .. "/" end + end + end + if parsed.is_absolute then path = "/" .. path end + return path +end + +return _M diff --git a/Me_Lua/h10/ssl.lua b/Me_Lua/h10/ssl.lua new file mode 100644 index 0000000..1cf2e39 --- /dev/null +++ b/Me_Lua/h10/ssl.lua @@ -0,0 +1,168 @@ +------------------------------------------------------------------------------ +-- LuaSec 0.5 +-- Copyright (C) 2006-2014 Bruno Silvestre +-- +------------------------------------------------------------------------------ + +local core = require("ssl.core") +local context = require("ssl.context") +local x509 = require("ssl.x509") + +module("ssl", package.seeall) + +_VERSION = "0.5.PR" +_COPYRIGHT = core.copyright() + +-- Export +loadcertificate = x509.load + +-- We must prevent the contexts to be collected before the connections, +-- otherwise the C registry will be cleared. +local registry = setmetatable({}, {__mode="k"}) + +-- +-- +-- +local function optexec(func, param, ctx) + if param then + if type(param) == "table" then + return func(ctx, unpack(param)) + else + return func(ctx, param) + end + end + return true +end + +-- +-- +-- +function newcontext(cfg) + local succ, msg, ctx + -- Create the context + ctx, msg = context.create(cfg.protocol) + if not ctx then return nil, msg end + -- Mode + succ, msg = context.setmode(ctx, cfg.mode) + if not succ then return nil, msg end + -- Load the key + if cfg.key then + if cfg.password and + type(cfg.password) ~= "function" and + type(cfg.password) ~= "string" + then + return nil, "invalid password type" + end + succ, msg = context.loadkey(ctx, cfg.key, cfg.password) + if not succ then return nil, msg end + end + -- Load the certificate + if cfg.certificate then + succ, msg = context.loadcert(ctx, cfg.certificate) + if not succ then return nil, msg end + end + -- Load the CA certificates + if cfg.cafile or cfg.capath then + succ, msg = context.locations(ctx, cfg.cafile, cfg.capath) + if not succ then return nil, msg end + end + -- Set SSL ciphers + if cfg.ciphers then + succ, msg = context.setcipher(ctx, cfg.ciphers) + if not succ then return nil, msg end + end + -- Set the verification options + succ, msg = optexec(context.setverify, cfg.verify, ctx) + if not succ then return nil, msg end + -- Set SSL options + succ, msg = optexec(context.setoptions, cfg.options, ctx) + if not succ then return nil, msg end + -- Set the depth for certificate verification + if cfg.depth then + succ, msg = context.setdepth(ctx, cfg.depth) + if not succ then return nil, msg end + end + + -- NOTE: Setting DH parameters and elliptic curves needs to come after + -- setoptions(), in case the user has specified the single_{dh,ecdh}_use + -- options. + + -- Set DH parameters + if cfg.dhparam then + if type(cfg.dhparam) ~= "function" then + return nil, "invalid DH parameter type" + end + context.setdhparam(ctx, cfg.dhparam) + end + -- Set elliptic curve + if cfg.curve then + succ, msg = context.setcurve(ctx, cfg.curve) + if not succ then return nil, msg end + end + -- Set extra verification options + if cfg.verifyext and ctx.setverifyext then + succ, msg = optexec(ctx.setverifyext, cfg.verifyext, ctx) + if not succ then return nil, msg end + end + + return ctx +end + +-- +-- +-- +function wrap(sock, cfg) + local ctx, msg + if type(cfg) == "table" then + ctx, msg = newcontext(cfg) + if not ctx then return nil, msg end + else + ctx = cfg + end + local s, msg = core.create(ctx) + if s then + core.setfd(s, sock:getfd()) + sock:setfd(core.invalidfd) + registry[s] = ctx + return s + end + return nil, msg +end + +-- +-- Extract connection information. +-- +local function info(ssl, field) + local str, comp, err, protocol + comp, err = core.compression(ssl) + if err then + return comp, err + end + -- Avoid parser + if field == "compression" then + return comp + end + local info = {compression = comp} + str, info.bits, info.algbits, protocol = core.info(ssl) + if str then + info.cipher, info.protocol, info.key, + info.authentication, info.encryption, info.mac = + string.match(str, + "^(%S+)%s+(%S+)%s+Kx=(%S+)%s+Au=(%S+)%s+Enc=(%S+)%s+Mac=(%S+)") + info.export = (string.match(str, "%sexport%s*$") ~= nil) + end + if protocol then + info.protocol = protocol + end + if field then + return info[field] + end + -- Empty? + return ( (next(info)) and info ) +end + +-- +-- Set method for SSL connections. +-- +core.setmethod("info", info) + diff --git a/Me_Lua/h10/ssl.so b/Me_Lua/h10/ssl.so new file mode 100644 index 0000000000000000000000000000000000000000..81e80a26598bee721290dbeb3a610871e622067c GIT binary patch literal 53826 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 G=>31L$sQ5_ literal 0 HcmV?d00001 diff --git a/Me_Lua/h10/ssl/https.lua b/Me_Lua/h10/ssl/https.lua new file mode 100644 index 0000000..d010669 --- /dev/null +++ b/Me_Lua/h10/ssl/https.lua @@ -0,0 +1,138 @@ +---------------------------------------------------------------------------- +-- LuaSec 0.5 +-- Copyright (C) 2009-2014 PUC-Rio +-- +-- Author: Pablo Musa +-- Author: Tomas Guisasola +--------------------------------------------------------------------------- + +local socket = require("socket") +local ssl = require("ssl") +local ltn12 = require("ltn12") +local http = require("socket.http") +local url = require("socket.url") + +local table = require("table") +local string = require("string") + +local try = socket.try +local type = type +local pairs = pairs +local getmetatable = getmetatable + +module("ssl.https") + +_VERSION = "0.5" +_COPYRIGHT = "LuaSec 0.5 - Copyright (C) 2009-2014 PUC-Rio" + +-- Default settings +PORT = 443 + +local cfg = { + protocol = "tlsv1", + options = "all", + verify = "none", +} + +-------------------------------------------------------------------- +-- Auxiliar Functions +-------------------------------------------------------------------- + +-- Insert default HTTPS port. +local function default_https_port(u) + return url.build(url.parse(u, {port = PORT})) +end + +-- Convert an URL to a table according to Luasocket needs. +local function urlstring_totable(url, body, result_table) + url = { + url = default_https_port(url), + method = body and "POST" or "GET", + sink = ltn12.sink.table(result_table) + } + if body then + url.source = ltn12.source.string(body) + url.headers = { + ["content-length"] = #body, + ["content-type"] = "application/x-www-form-urlencoded", + } + end + return url +end + +-- Forward calls to the real connection object. +local function reg(conn) + local mt = getmetatable(conn.sock).__index + for name, method in pairs(mt) do + if type(method) == "function" then + conn[name] = function (self, ...) + return method(self.sock, ...) + end + end + end +end + +-- Return a function which performs the SSL/TLS connection. +local function tcp(params) + params = params or {} + -- Default settings + for k, v in pairs(cfg) do + params[k] = params[k] or v + end + -- Force client mode + params.mode = "client" + -- 'create' function for LuaSocket + return function () + local conn = {} + conn.sock = try(socket.tcp()) + local st = getmetatable(conn.sock).__index.settimeout + function conn:settimeout(...) + return st(self.sock, ...) + end + -- Replace TCP's connection function + function conn:connect(host, port) + try(self.sock:connect(host, port)) + self.sock = try(ssl.wrap(self.sock, params)) + try(self.sock:dohandshake()) + reg(self, getmetatable(self.sock)) + return 1 + end + return conn + end +end + +-------------------------------------------------------------------- +-- Main Function +-------------------------------------------------------------------- + +-- Make a HTTP request over secure connection. This function receives +-- the same parameters of LuaSocket's HTTP module (except 'proxy' and +-- 'redirect') plus LuaSec parameters. +-- +-- @param url mandatory (string or table) +-- @param body optional (string) +-- @return (string if url == string or 1), code, headers, status +-- +function request(url, body) + local result_table = {} + local stringrequest = type(url) == "string" + if stringrequest then + url = urlstring_totable(url, body, result_table) + else + url.url = default_https_port(url.url) + end + if http.PROXY or url.proxy then + return nil, "proxy not supported" + elseif url.redirect then + return nil, "redirect not supported" + elseif url.create then + return nil, "create function not permitted" + end + -- New 'create' function to establish a secure connection + url.create = tcp(url) + local res, code, headers, status = http.request(url) + if res and stringrequest then + return table.concat(result_table), code, headers, status + end + return res, code, headers, status +end