From af32a36f1c75a55813bcacf4746e3b08080508f5 Mon Sep 17 00:00:00 2001 From: Nilsonlinux Date: Sun, 9 Aug 2026 14:50:32 -0300 Subject: [PATCH] Add nilsonlinux/link-ip-monitor v1.0.0 (#320) * Add nilsonlinux/link-ip-monitor v1.0.0 * Add nilsonlinux/link-ip-monitor v1.0.0 * Update plugin ID in README.md * Rename project to link-ip-monitor and update ID Updated the project name and ID in the README. * Update plugin ID and command syntax in README --- link-ip-monitor/README.md | 64 +++++ link-ip-monitor/panel.luau | 359 ++++++++++++++++++++++++ link-ip-monitor/plugin.toml | 76 +++++ link-ip-monitor/service.luau | 307 ++++++++++++++++++++ link-ip-monitor/thumbnail.webp | Bin 0 -> 76752 bytes link-ip-monitor/translations/en.json | 49 ++++ link-ip-monitor/translations/pt-BR.json | 49 ++++ link-ip-monitor/widget.luau | 87 ++++++ 8 files changed, 991 insertions(+) create mode 100644 link-ip-monitor/README.md create mode 100644 link-ip-monitor/panel.luau create mode 100644 link-ip-monitor/plugin.toml create mode 100644 link-ip-monitor/service.luau create mode 100644 link-ip-monitor/thumbnail.webp create mode 100644 link-ip-monitor/translations/en.json create mode 100644 link-ip-monitor/translations/pt-BR.json create mode 100644 link-ip-monitor/widget.luau diff --git a/link-ip-monitor/README.md b/link-ip-monitor/README.md new file mode 100644 index 0000000..39cf6e4 --- /dev/null +++ b/link-ip-monitor/README.md @@ -0,0 +1,64 @@ +# link-ip-monitor +link-ip-monitor pings a list of IPs, hostnames or links on an interval, tracks +each host's online/offline status and response time, and notifies when one +goes down or comes back up. + +## Plugin +| Field | Value | +| --- | --- | +| ID | `nilsonlinux/link-ip-monitor` | +| Entries | Bar widget: `status`; panel: `panel`; service: `monitor` | + +## Requirements +Uses the system `ping` binary (`iputils`, present on most Linux distros). +No other external dependency. + +## Usage +Add the `status` widget to the bar: it turns green when every monitored +host is responding, red with a count badge when one or more are down, and +neutral when the list is empty. + +Click the widget to open the panel. Use the `+` button in the panel header +to reveal the add-host form — accepts an IP (`8.8.8.8`), a hostname +(`example.com`) or a full link (scheme, port, path and query are stripped +automatically, keeping only the host to ping). An optional description can +be set alongside it. + +Each row in the panel shows the label (or the host, if no label was set), a +status pill, the response time in ms while online, a drag handle to +reorder the list, and a trash button to remove that entry (asks for +confirmation). Right-click the widget, or use the refresh button in the +panel, to force an immediate check. + +Open the panel directly with: +```sh +noctalia msg panel-toggle nilsonlinux/link-ip-monitor:panel +``` + +Force an immediate check via IPC: +```sh +noctalia msg plugin nilsonlinux/link-ip-monitor:monitor all refresh +``` + +The host list itself is not stored in plugin settings — it lives in the +service's own persisted state (`pluginDataDir()/state.json`) and is +managed entirely from the panel (add / remove / reorder), since the +plugin API has no way to write settings back from a script. + +## Settings +| Setting | Type | Default | Description | +| --- | --- | --- | --- | +| `interval_seconds` | `int` | `30` | How often each host is checked. | +| `timeout_seconds` | `int` | `1` | How long to wait for a ping reply before treating it as a failure. | +| `notify_on_recovery` | `bool` | `true` | Send a notification when a host that was down responds again. | +| `glyph` (widget) | `glyph` | `activity` | Icon shown in the bar for the `status` widget. | + +## Notes +Notification text and panel labels come from `translations/.json` +via `noctalia.tr()` (English and `pt-BR` included). `noctalia.notify()` / +`noctalia.notifyError()` accept only a title and body — the plugin API +exposes no urgency parameter, so the "host down" alert's appearance (the +red border from `notifyError`) can't be further customized from the +plugin. Response time (ms) is parsed from `ping`'s own text output, so it +depends on that output containing a `= ms` pattern regardless of +the system's locale. diff --git a/link-ip-monitor/panel.luau b/link-ip-monitor/panel.luau new file mode 100644 index 0000000..a01f367 --- /dev/null +++ b/link-ip-monitor/panel.luau @@ -0,0 +1,359 @@ +--!nonstrict +-- panel.luau +-- Window shown when clicking the bar widget: a form to add an IP, +-- hostname or link (with an optional description field below it), and +-- the list of monitored hosts — each with its label (if set), a status +-- pill, response time in ms (when online), a drag handle to reorder, and +-- a remove button (with confirmation). + +local ips = {} -- { {ip=, label=, status=, latency_ms=}, ... } +local draftIp = "" +local draftLabel = "" +local draftKey = 0 +local draftError = "" +local pendingDelete = nil +local showAddForm = false + +local DRAG_TYPE = "link-ip-monitor-host" + +local STATUS_COLORS = { + up = { fill = "#2e7d32", text = "#ffffff" }, + down = { fill = "#c62828", text = "#ffffff" }, + checking = { fill = "#5f6368", text = "#ffffff" }, +} + +local render + +-- Accepts an IP, a plain hostname, or a link (http://..., https://...) +-- and returns just the host — scheme, port, path and query are dropped. +-- Same logic as service.luau (duplicated here just to give immediate +-- feedback in the field). +local function extractHost(raw) + local s = noctalia.string.trim(raw or "") + s = s:gsub("^%a[%w+.-]*://", "") + s = s:match("^([^/%?#]+)") or s + s = s:match("^([^:]+)") or s + return s +end + +local function isValidIPv4(host) + local a, b, c, d = host:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$") + if not a then + return false + end + for _, n in ipairs({ a, b, c, d }) do + local num = tonumber(n) + if num == nil or num < 0 or num > 255 then + return false + end + end + return true +end + +local function isValidHostname(host) + if host == "" or #host > 253 then + return false + end + local labelCount = 0 + for label in host:gmatch("[^%.]+") do + labelCount = labelCount + 1 + if #label == 0 or #label > 63 then + return false + end + if not label:match("^%w[%w%-]*%w$") and not label:match("^%w$") then + return false + end + end + return labelCount > 0 +end + +local function normalizeHost(raw) + local host = extractHost(raw) + if host == "" then + return nil + end + if isValidIPv4(host) or isValidHostname(host) then + return host + end + return nil +end + +local STATUS_TR_KEY = { + up = "panel.status_online", + down = "panel.status_offline", + checking = "panel.status_checking", +} + +local function pill(status) + local colors = STATUS_COLORS[status] or STATUS_COLORS.checking + local label = noctalia.tr(STATUS_TR_KEY[status] or "panel.status_checking") + return ui.row({ + fill = colors.fill, + radius = 8, + paddingH = 8, + paddingV = 2, + align = "center", + justify = "center", + }, { + ui.label({ text = label, fontSize = 11, fontWeight = "bold", color = colors.text }), + }) +end + +-- Thin strip between rows (and before the first / after the last) that +-- accepts a dropped host, indicating where it will land. +local function insertionZone(index) + return ui.dropZone({ + key = "gap-" .. index, + accepts = { DRAG_TYPE }, + value = tostring(index), + onDrop = "onIpDropped", + height = 3, + radius = 4, + expandOnDrag = true, + hitSlop = 24, + }) +end + +function onIpDropped(payload, value) + local insertAt = tonumber(value) + if type(payload) ~= "string" or payload == "" or insertAt == nil then + return + end + noctalia.state.set("link_ip_monitor.cmd", { op = "reorder", ip = payload, index = insertAt }) +end + +local function hostRow(item) + local id = item.ip + local deleting = pendingDelete == id + + local actions + if deleting then + actions = ui.row({ gap = 4, align = "center" }, { + ui.button({ + glyph = "check", + variant = "destructive", + controlSize = "sm", + tooltip = noctalia.tr("panel.tooltip_confirm_remove"), + onClick = function() + noctalia.state.set("link_ip_monitor.cmd", { op = "remove", ip = id }) + pendingDelete = nil + render() + end, + }), + ui.button({ + glyph = "close", + variant = "ghost", + controlSize = "sm", + tooltip = noctalia.tr("panel.tooltip_cancel"), + onClick = function() + pendingDelete = nil + render() + end, + }), + }) + else + actions = ui.button({ + glyph = "trash", + variant = "ghost", + controlSize = "sm", + tooltip = noctalia.tr("panel.tooltip_remove"), + onClick = function() + pendingDelete = id + render() + end, + }) + end + + -- Left column: label (if set) in bold + host as a caption; without a + -- label, the host becomes the main text. + local infoChildren = {} + local hasLabel = item.label ~= nil and item.label ~= "" + if hasLabel then + table.insert(infoChildren, ui.label({ text = item.label, fontWeight = "bold", fontSize = 13 })) + table.insert(infoChildren, ui.label({ text = item.ip, color = "on_surface_variant", fontSize = 10 })) + else + table.insert(infoChildren, ui.label({ text = item.ip, fontWeight = "bold", fontSize = 13 })) + end + + -- Right column: status pill + response time in ms (only while online + -- and when the measurement exists). + local statusChildren = { pill(item.status) } + if item.status == "up" and item.latency_ms ~= nil then + table.insert(statusChildren, ui.label({ + text = tostring(math.floor(item.latency_ms + 0.5)) .. " ms", + fontSize = 10, + color = "on_surface_variant", + })) + end + + return ui.row({ + key = "ip-" .. id, + gap = 8, + padding = 10, + radius = 8, + fill = "surface_variant/0.35", + align = "center", + justify = "space_between", + }, { + ui.dragSource({ + key = "grip-" .. id, + dragType = DRAG_TYPE, + payload = id, + previewAncestor = 1, + liftFromLayout = true, + width = 20, + height = 20, + align = "center", + justify = "center", + tooltip = noctalia.tr("panel.tooltip_drag"), + }, { + ui.glyph({ name = "menu-2", size = 14, color = "on_surface_variant" }), + }), + ui.column({ flexGrow = 1, gap = 1 }, infoChildren), + ui.column({ align = "end", gap = 2 }, statusChildren), + actions, + }) +end + +local function emptyState() + return ui.column({ gap = 10, align = "center", padding = 32, flexGrow = 1, justify = "center" }, { + ui.glyph({ name = "activity", size = 32, color = "outline" }), + ui.label({ text = noctalia.tr("panel.empty"), color = "outline" }), + }) +end + +render = function() + local body + + if #ips == 0 then + body = emptyState() + else + local rows = {} + for i, item in ipairs(ips) do + table.insert(rows, insertionZone(i)) + table.insert(rows, hostRow(item)) + end + table.insert(rows, insertionZone(#ips + 1)) + body = ui.scroll({ gap = 6, flexGrow = 1 }, rows) + end + + local column = {} + + table.insert(column, ui.row({ align = "center", justify = "space_between" }, { + ui.label({ text = noctalia.tr("title"), fontSize = 16, fontWeight = "bold", flexGrow = 1 }), + ui.button({ + glyph = showAddForm and "minus" or "plus", + variant = showAddForm and "primary" or "ghost", + controlSize = "sm", + tooltip = showAddForm and noctalia.tr("panel.tooltip_close_form") or noctalia.tr("panel.tooltip_add_host"), + onClick = function() + showAddForm = not showAddForm + if not showAddForm then + draftIp = "" + draftLabel = "" + draftError = "" + draftKey += 1 + end + render() + end, + }), + ui.button({ + glyph = "refresh", + variant = "ghost", + controlSize = "sm", + tooltip = noctalia.tr("panel.tooltip_check_now"), + onClick = function() noctalia.state.set("link_ip_monitor.cmd", { op = "refresh" }) end, + }), + ui.button({ + glyph = "close", + variant = "ghost", + controlSize = "sm", + onClick = function() panel.close() end, + }), + })) + + if showAddForm then + table.insert(column, ui.row({ + gap = 6, + align = "center", + padding = 8, + radius = 8, + fill = "surface_variant/0.35", + }, { + ui.column({ flexGrow = 1, gap = 6 }, { + ui.input({ + key = "add-ip-" .. draftKey, + value = draftIp, + placeholder = noctalia.tr("panel.add_placeholder"), + onChange = function(value) draftIp = value; draftError = "" end, + onSubmit = "onAdd", + }), + ui.input({ + key = "add-label-" .. draftKey, + value = draftLabel, + placeholder = noctalia.tr("panel.add_label_placeholder"), + onChange = function(value) draftLabel = value end, + onSubmit = "onAdd", + }), + (draftError ~= "" and ui.label({ text = draftError, color = "#e05252", fontSize = 11 }) or nil), + }), + ui.button({ glyph = "plus", variant = "primary", controlSize = "sm", tooltip = noctalia.tr("panel.tooltip_add"), onClick = "onAdd" }), + })) + end + + table.insert(column, body) + + panel.render(ui.column({ gap = 8, padding = 8, flexGrow = 1 }, column)) +end + +function onAdd() + local host = normalizeHost(draftIp) + if noctalia.string.trim(draftIp) == "" then + return + end + if host == nil then + draftError = noctalia.tr("panel.invalid_format") + showAddForm = true + render() + return + end + + local label = noctalia.string.trim(draftLabel) + draftIp = "" + draftLabel = "" + draftKey += 1 + draftError = "" + showAddForm = false + noctalia.state.set("link_ip_monitor.cmd", { op = "add", ip = host, label = label }) + render() +end + +function onOpen(_context) + ips = noctalia.state.get("link_ip_monitor.statuses") or {} + pendingDelete = nil + draftIp = "" + draftLabel = "" + draftError = "" + draftKey += 1 + showAddForm = false + render() +end + +noctalia.state.watch("link_ip_monitor.statuses", function(value) + ips = (type(value) == "table") and value or {} + + if pendingDelete ~= nil then + local stillThere = false + for _, item in ipairs(ips) do + if item.ip == pendingDelete then + stillThere = true + break + end + end + if not stillThere then + pendingDelete = nil + end + end + + render() +end) diff --git a/link-ip-monitor/plugin.toml b/link-ip-monitor/plugin.toml new file mode 100644 index 0000000..d8d31a7 --- /dev/null +++ b/link-ip-monitor/plugin.toml @@ -0,0 +1,76 @@ +id = "nilsonlinux/link-ip-monitor" +name = "Link/IP Monitor" +version = "1.0.0" +plugin_api = 14 +author = "Nilsonlinux" +license = "MIT" +icon = "activity" +description = "It pings a list of IPs, hosts, or links at intervals and notifies you when one goes down (or comes back up)." +tags = ["network", "indicator", "bar", "panel", "service"] +dependencies = ["ping"] + +# --------------------------------------------------------------------------- +# Plugin settings: shared by ALL entries (service + widget). Edited in +# Settings -> Plugins. +# --------------------------------------------------------------------------- + +[[setting]] +key = "interval_seconds" +type = "int" +label_key = "settings.interval_seconds.label" +description_key = "settings.interval_seconds.description" +default = 30 +min = 5 +max = 3600 + +[[setting]] +key = "timeout_seconds" +type = "int" +label_key = "settings.timeout_seconds.label" +description_key = "settings.timeout_seconds.description" +default = 1 +min = 1 +max = 10 + +[[setting]] +key = "notify_on_recovery" +type = "bool" +label_key = "settings.notify_on_recovery.label" +description_key = "settings.notify_on_recovery.description" +default = true + +# --------------------------------------------------------------------------- +# Service: runs in the background, pings hosts, and publishes state +# --------------------------------------------------------------------------- + +[[service]] +id = "monitor" +entry = "service.luau" + +# --------------------------------------------------------------------------- +# Bar widget: icon with a badge for the number of hosts that are down +# --------------------------------------------------------------------------- + +[[widget]] +id = "status" +entry = "widget.luau" + +[[widget.setting]] +key = "glyph" +type = "glyph" +label_key = "settings.glyph.label" +description_key = "settings.glyph.description" +default = "activity" + +# --------------------------------------------------------------------------- +# Panel: list of hosts with a status pill, opened by clicking the widget +# --------------------------------------------------------------------------- + +[[panel]] +id = "panel" +entry = "panel.luau" +width = 320 +height = 400 +placement = "attached" +position = "auto" +open_near_click = true diff --git a/link-ip-monitor/service.luau b/link-ip-monitor/service.luau new file mode 100644 index 0000000..bdec324 --- /dev/null +++ b/link-ip-monitor/service.luau @@ -0,0 +1,307 @@ +--!nonstrict +-- service.luau +-- Headless service: keeps the host list (IP, hostname or link — each with +-- an optional label), pings every entry, measures latency, and notifies +-- on the up -> down transition (and, when enabled, down -> up). +-- +-- Persistence: pluginDataDir()/state.json ({ ips = { {ip=, label=}, ... } }) +-- State: link_ip_monitor.statuses = { {ip=, label=, status=, latency_ms=}, ... } +-- link_ip_monitor.down_count = number +-- Panel commands: ip_monitor.cmd = +-- { op = "add"|"remove"|"refresh"|"reorder", ip = "...", label? = "...", index? = N } + +local ipList = {} -- { {ip=, label=}, ... } — "ip" here is the already-normalized host (no scheme/port/path) +local hostState = {} -- host -> true (up) / false (down) / nil (not checked yet) +local hostLatency = {} -- host -> latency in ms (number) / nil +local dataPath = nil + +local function trim(s) + return noctalia.string.trim(s or "") +end + +-- Validates IPv4 in N.N.N.N form, each octet between 0 and 255. +local function isValidIPv4(host) + local a, b, c, d = host:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$") + if not a then + return false + end + for _, n in ipairs({ a, b, c, d }) do + local num = tonumber(n) + if num == nil or num < 0 or num > 255 then + return false + end + end + return true +end + +-- Validates a hostname (dot-separated labels, letters/digits/hyphen, no +-- leading/trailing hyphen per label). +local function isValidHostname(host) + if host == "" or #host > 253 then + return false + end + local labelCount = 0 + for label in host:gmatch("[^%.]+") do + labelCount = labelCount + 1 + if #label == 0 or #label > 63 then + return false + end + if not label:match("^%w[%w%-]*%w$") and not label:match("^%w$") then + return false + end + end + return labelCount > 0 +end + +-- Accepts an IP, a plain hostname, or a link (http://..., https://...) +-- and returns just the host — scheme, port, path and query are dropped. +-- That clean host is what actually becomes the ping target (ping doesn't +-- understand a full URL). +local function extractHost(raw) + local s = trim(raw) + s = s:gsub("^%a[%w+.-]*://", "") -- strip a scheme like http:// or https:// + s = s:match("^([^/%?#]+)") or s -- cut path/query/fragment + s = s:match("^([^:]+)") or s -- cut an explicit port (host:port) + return s +end + +local function normalizeHost(raw) + local host = extractHost(raw) + if host == "" then + return nil + end + if isValidIPv4(host) or isValidHostname(host) then + return host + end + return nil +end + +local function indexOfIp(ip) + for i, entry in ipairs(ipList) do + if entry.ip == ip then + return i + end + end + return nil +end + +local function loadState() + local dir = noctalia.pluginDataDir() + if dir == nil then + return + end + dataPath = dir .. "/state.json" + + local raw = noctalia.readFile(dataPath) + if raw ~= nil then + local ok, decoded = pcall(noctalia.json.decode, raw) + if ok and type(decoded) == "table" and type(decoded.ips) == "table" then + for _, entry in ipairs(decoded.ips) do + if type(entry) == "table" and type(entry.ip) == "string" then + table.insert(ipList, { ip = entry.ip, label = trim(entry.label) }) + elseif type(entry) == "string" then + -- backward compatibility with the old format (list of plain strings, no label) + table.insert(ipList, { ip = entry, label = "" }) + end + end + end + end + -- no file yet (first run): ipList stays empty until the user adds + -- something from the panel. +end + +local function saveState() + if dataPath == nil then + return + end + local ok, encoded = pcall(noctalia.json.encode, { ips = ipList }) + if ok and type(encoded) == "string" then + pcall(noctalia.writeFile, dataPath, encoded) + end +end + +local function publishState() + local statuses = {} + local downCount = 0 + + for _, entry in ipairs(ipList) do + local up = hostState[entry.ip] + local status + if up == true then + status = "up" + elseif up == false then + status = "down" + downCount = downCount + 1 + else + status = "checking" + end + + table.insert(statuses, { + ip = entry.ip, + label = entry.label, + status = status, + latency_ms = (status == "up") and hostLatency[entry.ip] or nil, + }) + end + + noctalia.state.set("link_ip_monitor.statuses", statuses) + noctalia.state.set("link_ip_monitor.down_count", downCount) +end + +local function checkHost(entry) + local ip = entry.ip + local timeout = noctalia.getConfig("timeout_seconds") or 1 + -- -c 1: send 1 packet; -W: timeout in seconds (iputils/Linux). ping + -- resolves a hostname via DNS normally, so a host like "example.com" + -- (extracted from a link) works just like an IP. + local cmd = string.format("ping -c 1 -W %d %s", timeout, ip) + + noctalia.runAsync(cmd, function(res) + local success = res.exitCode == 0 + + local latency = nil + if success and type(res.stdout) == "string" then + -- Ignores the word before "=" or "<" (time=, tempo=, temps=...) — + -- ping's output changes with the system locale. Only looks for the + -- number that comes right before "ms". + local ms = res.stdout:match("[=<]%s*(%d+%.?%d*)%s*ms") + latency = ms and tonumber(ms) or nil + end + + local wasUp = hostState[ip] + hostState[ip] = success + hostLatency[ip] = latency + + if wasUp ~= success then + local display = (entry.label ~= "" and entry.label) or ip + if success == false then + noctalia.notifyError(noctalia.tr("title"), noctalia.tr("notify.host_down", { host = display })) + elseif wasUp == false and success == true and noctalia.getConfig("notify_on_recovery") then + noctalia.notify(noctalia.tr("title"), noctalia.tr("notify.host_up", { host = display })) + end + end + + publishState() + end, (timeout + 2) * 1000) +end + +local function checkAll() + for _, entry in ipairs(ipList) do + checkHost(entry) + end +end + +local function applyInterval() + local seconds = noctalia.getConfig("interval_seconds") or 30 + noctalia.setUpdateInterval(seconds * 1000) +end + +-- Returns ok, reason ("invalid" | "duplicate") on failure. +local function addIp(raw, label) + local host = normalizeHost(raw) + if host == nil then + return false, "invalid" + end + if indexOfIp(host) ~= nil then + return false, "duplicate" + end + local entry = { ip = host, label = trim(label) } + table.insert(ipList, entry) + saveState() + publishState() + checkHost(entry) + return true +end + +local function removeIp(ip) + local idx = indexOfIp(ip) + if idx ~= nil then + table.remove(ipList, idx) + end + hostState[ip] = nil + hostLatency[ip] = nil + saveState() + publishState() +end + +-- Moves `ip` to 1-based position `index` in the final list (drag and drop +-- in the panel) — same logic as the official world_clock's reorderZone(). +local function reorderIp(ip, index) + local fromIdx = indexOfIp(ip) + if fromIdx == nil then + return false + end + local insertAt = tonumber(index) + if insertAt == nil then + return false + end + local entry = table.remove(ipList, fromIdx) + if fromIdx < insertAt then + insertAt -= 1 + end + insertAt = math.max(1, math.min(insertAt, #ipList + 1)) + table.insert(ipList, insertAt, entry) + saveState() + publishState() + return true +end + +-- --------------------------------------------------------------------------- +-- Commands coming from the panel, via noctalia.state (same pattern as the +-- official world_clock: the panel sets "ip_monitor.cmd", the service +-- watches it, processes it, and clears it back to nil). +-- --------------------------------------------------------------------------- + +noctalia.state.watch("link_ip_monitor.cmd", function(cmd) + if type(cmd) ~= "table" then + return + end + local op = cmd.op + if op == "add" then + local ok, reason = addIp(cmd.ip, cmd.label) + if not ok then + local display = tostring(cmd.ip or "") + if reason == "invalid" then + noctalia.notifyError(noctalia.tr("title"), noctalia.tr("notify.invalid_host", { host = display })) + elseif reason == "duplicate" then + noctalia.notifyError(noctalia.tr("title"), noctalia.tr("notify.duplicate_host", { host = display })) + end + end + elseif op == "remove" then + removeIp(cmd.ip) + elseif op == "reorder" then + reorderIp(cmd.ip, cmd.index) + elseif op == "refresh" then + checkAll() + end + noctalia.state.set("link_ip_monitor.cmd", nil) +end) + +-- --------------------------------------------------------------------------- +-- Lifecycle +-- --------------------------------------------------------------------------- + +loadState() +applyInterval() +publishState() +checkAll() + +function update() + checkAll() +end + +function onConfigChanged() + applyInterval() +end + +-- Still works via CLI too, if needed: +-- noctalia msg plugin nilsonlinux/link-ip-monitor:monitor all refresh +function onIpc(event, payload) + if event == "refresh" then + checkAll() + elseif event == "add" and payload then + addIp(payload, "") + elseif event == "remove" and payload then + removeIp(payload) + end +end diff --git a/link-ip-monitor/thumbnail.webp b/link-ip-monitor/thumbnail.webp new file mode 100644 index 0000000000000000000000000000000000000000..462b1126d488a4808cdadbf69e71d3b263914cbb GIT binary patch literal 76752 zcmWIYbaOkQ&Bze$>J$(bV4<)_n~~wdH0HUCS_hbAnCv*28XX$l7#IYmm92}Y{q#Be zs@DIRdmX;@KH&^3cdBAsVs?{z{&O3(YW^3oht?_O%-JjZojvxy&42wT>nqQ!e_#K) zF6iI0`a?f&KehX9XZR@op8mK0we{Cu%fGUJTX~@B`uq8>?GOB4_&@TW{r}}x<$u|K zvAZSvpkU)LY~!TnG8U;MxM zciuO~U)aCx|B3&G|Mvg;ewO|B{-5`s)js}T_22t{|DW_<@e}-?%irEt|L=4C`~TO! zyZzVv&;0NBpZN{zpZ&kS|N7thzbERi|3Cll`ako3=a<#Lx&Q9}r~j+|NB(brQT{9Z z`~4sG+w8y9*Z(_U|M7QdJ;VRiuNYs-KfV8J|Drm@e-~@*e#T$Zzjpq0{r&&vtA&3~ zzq-Hm-|yd=e~3fBo-jRqvn8Z`<$f-}}G!zwqDR|I&Z+FR6d} zfBE0OzlZ;Ce z{6>41|APOR|GNM9|Dpaz{ms9gf4BeMe~Q1}zVg52fAvq%FSvi2f8PJ@|E>Du`hEZ3 z{P+I;{O|qWbsqMU|Id8G`e*wu_aEoq|9|oST7C2Xx8Gj>GymiNrT)$T+x6}LpZ~l6 z^!b(ekM-yOZ~foS|4``>C$*WIeW_g(LA z;{W2GtAGFhe>cf#10y)RR|`6T&(^nX78&F#L4^WW-B$=jM{)uy?Q;k}h> z*CJF;@B4Y|efKGb zc<+5Cxm`{!L1=E#B1I>0|96wu>nL6}HD2>F@VA!PCe=F^r&s)|{yzC?%-<=;b6S?} z{5#(wdfJU08oD1YC2ck`OsF){N)ypiJfa&S?)diN6vJa*t1n&rCS^3gO84}4hvxU1 zvCYdI=iFpI9^5+3IT!cWUovm2h%t+_F9B>8HkH4N;Od1($vJXKah#b@*t;=Aw&d zr0dVU{ZkZo;XrGXmA>0?p*m(g{r`)RtDxgR&U`5?SEK2r;!3;A z5Atg!ahJsW;?|F~4ZF+YB(kLVIs0p*11slaz<6)E~a*!pSGrYYVuad0rXn(r%~VY;ixU%S3L!xuyJK_L;6>inEh% zpVof&d!5|%g|oz;ujppH`j2l(?dPB;9RCELhs&-#@jJ_I`E;fv9qoVXORCER-=7Y8 z)+{`GQTTJ^YrB3&)yQWp>busk=zMf-0W$)9lw%NP#8&A#1>R4rbxL=;Zu;bQ_7>AOKxg{4FE0^po`Wz#md(m=U zeQ}5kw~4~#MSib8EY)b~ULa+%BjstO@Vg9AMNacxanaA~tFn7~_I}tPXYgm;{ab2Z z+(gv;JZB_tY~J^&ykANyPT*C7+{w3XcMmGPvHHE`N04(6Yrv-;zQT|1n^?D>_YYiS zRg#{#@^tBB-~aC)y)HiX-TbwMvhbI^dv~=z)_6SEedh~H*SyINCYLAK=j{%eCKLU; z^mg$^gGt|}dD`5Nb8*%G^0(AWWd6UGS59rcP#49pm)8Gij?K6!8HMxPJIR{XznCpJ!Y6I-{bK*o)PD@T0JNj=!X`E~B>TQ1d z#D}Fj_T(!DJI06=$KM^xToCd5-Ih~Ndb56bMi=UNtCwgi8HqpxBXr{;I{67D30?tS%q4s-n54;Od*IoKOBEja%_ z*S$#*N=G#QCYI0PynOKUG)>D7g0r>0$1CV{i?H$W{pEWW*(@JeAAerz?wpPF$Hexi zyt*oxaUgMfp2Z9u%bT5>R3rCtPiyw|+dAz}`>QwE%QsElBf4-}-1FsH&9+|G=PWW} z%a%O<(sb(mc}|uIr#AJK$*k1=Zt3Fn(=RDSpyp<0!X0zR=civ?pSm^l*}^3`>+T=^ ztn0i&Fv{9w$#eFcPc;emXaAdC*_5qlppsatWU^gG`0xvjjZ9wx=LGm4*Ov)+sb|00 zw9cg3t|aB>F^^6qRo=b#AAC48oyYu~K+nIUO1iw$GRlj~Z@90>UR`GJaUJi0PnHQA zbG?!-ezWQjK4EVc|H1gWjl0h3M~8K}KJ8Yi_S62m>eaP#ye9U^-rB{DMm`E<`<}67 zGX|OptqFY=>{{=U^I~>@aB}=la|b6^s{>&6QT(sn91fj- z`|-BsR|2-dIfupc4w(Fqx%X&xx!uC$TfWrrZa){k$AUyP-H z^LD-2{IP$P8H?G|tFaXZemZG3x0*=(=gV!pnKtF@0^ ztX5K;_55X1iqh@CYe4@wStnJUaS{q+>pH! zB)hzWe^zL4wQGV8zl7+PiNAfyzP_)kt!F>Kd@dK;hU1?LLfT*S^xd^`)KIHn&^I{C zlHzY%*sb!CyFN8-|61*aNAG{?f0A{&`m~@cY}?X~U|Hs*jK9pL>D-<_dj;;6S!GVD zUUX{F^Ia^?aLsZ@9H^qpF5o=Hk~iQYW6}tqJ8a-JNjq-5lu~VbNc=1^nkZ$lB(clVg;Yd?T-q zW!*;UbI0u?@0k4mZs@dP-O6fBR@Q3w8GGDhZdV-ak55?b{fj4i?foW?74u_yFaKWi zqius$b2$f3Iroi|+;1LaygHXsY&N|<+wRqDF_|=bSC{qk)4X)cL}btA82MXWyx&+F zTJpbo|0j+%6r-uY&ANI`UTW+*xLyJ{?azF0Fs? zYBh6C+Kn0EJ9cWWj?6ci)UeZd3+ub?zrVy&b6b9g*yM|OIo{XUyL_JbmL{fqbM%gc zSvqX56MA48Hq$oK`{T6$`M0cVj?Y>6HfGW5*X{{NF0gfOtIs{DVj?N!ReWi$U8e7x z9l!ewS4SLpGuvm={{vTUt~<~xaQ>G^?1h{y+f+S+*gI@i-xUt_3_lq2HSXXSWr6%T z+pZ|_=}vf8+A)9jzTlZNUu=2exT~?a@|skEQgPCa`c+PCpL}Xe-rTt2aqPUW;3uO= zTg?2j)`~ta;fz|lSMu1?oYLH`Tb5T2E(^M#yyngQ$mql8!~SS~m=$_{-AeyI@%uOO zZr|;HT#V`Ni}crmjYT%Ao?H&Kid@2dwWB)FUenK1S~x)}X`5V&vUb6?f47eKn=GGm zXR)H9#Jn>pir)ezCa~T4WizQOwpc3SyQTVtS=mmxOXgPOoi)2{>Lan;W6x@#|AvdJ zlT*cuUsQFA&s?3Ol2OpGa_W~8ZC^LPQ0`sWti0+8tNg>`Oc$P)xJjP-Kf6FmF*?>K zErTm>cR-2z^wh%__83I&dCtbA&&ZL;_;L4-XJLWg;&=X$`>m!cvUD$nr$^^m-K&53$$RhgZWpO1n|>-U%1VA8>z~-|WX6;{H%dMr zdX~w)zuAe`ub<9a#nAooj-vIUxt)HdX7w$>UMKXqIarH}y1vOx`1yJHGgIs9k$)SW z+|Wyv-L1~moH(DI^~BL;E6MHK;-)6tabT^z!&<77DzLlzj~|~ER?h#@ z!1AG%#YDNUuIn6g{bsXu$znTuUMfh>>d~FNX3~b=!lKt&Ha?nx3a&Lv`?@(U7o(ZJ<>YsihTLRMcLcdAD%0zGx5lsdm-1Vz3#35 zp~?5xYTeA>mE6tKSBqBbB;2uJsIvXHti{CWUcqkbwJWAN^L9_U%>8xknY`^!-pPl= zd^>6B?!*!&v+E&Se%$9{9feZoFRVL0zekKqri`;XVAgIoMuYWR!#+MU3z_%QexDA< z7RKDWtA9TFZSYd*?TxzgD$7@!t=#y}uxx(Bv5zNK^Y823@h!;3b$Rb5jTJj%3s*kt z@GWyml(bnRJt2|S^ZlFATQ{!hNk1ekzB*0~S5><* zRd?2!tiLHXQ`B}hG#_Iz)35kmmbHa%kx*8=gEMo7T>|zazW(tBLVZXJrP)s0q#6 z=lq#;@bll`iHdV3&vc9MWV7DcJEWs>anYd)(_ zYH`|C$cKvUs9oQ2si^JiQ;%my-%WbF*W+C%g}RWFco)TF13( zz4-65wzp;+tK)q6P{c4@aYD^4TlUF211=vge0S=g--&F+zJ+l?!mF3eQ)AiPd1Z@5 z&?za$$-Z5EIvz#*8z;W3K5fFQS{wKG(6;}l?aIx{XZd#3FGyFndaSg!(xmp2nQ^G* z%#Ck@ZvT7d^(6nc^PC_y5w2M;_hc@L{#kH6!N_&d|MLCXEut%oR28l|d28MG2!3#1 zUEs)@!q*QD#$Q~b@!+5Jj^?v}Z2PpAK}tm$kFO7aMupxRc&r1yiJ^WVjb z7PEG5dwSZt*S0RXKsi(@{!o{8zgd>N|9<6d_0OhXy;hPDViMQw;Be&sM3=deF25$f zOiZ6q?V>dKkP3s)EM1lRetjR4XUFq#$i{dw?>mwt_GEA1Y|*%@6aShXSSif<{GGtm z_oa3+lOJ7Obt;H=sYuGR>AREO?!VUg>c{PcO0k>8*R6i5@c-+)$U-R_wmILUx5-$q zV2Im(W0rS~*$d&99~&+|jr(f5V!!^RpKG7`>rOpXerWBkl`Awayf4c0pY!+h{H6B) zuAjL*p;E$7_fDdg&+(AUtGK2fVfOme`!(07*yWaZ^oF0IsY?tsR7IOyn$~?4*l@?B zJ+)rsxOM)vPtQ9S99b>9MW^SI>3`1xrJxHsbz5Y*KLz=-=Umwx(_ZO#USS)b>i)Go z7yQ~<6C)B6BSh^IKWq<}UH{UmA;qCWRXF3#SB^cRyy1(u|4hsXU;0p)hx6*sP%gic zj`G_V#h%uvU2UCmX5~C3Q_rVbGrj+CvYfs%fipDLw`#eH|II}c4>qxte)~BgM$jhZ z`YjICJDHLz{@gtp80KvBijV8~{Xm=PLRFWnq8%O!-)g^ZH*3xI6MT#MW}N;u^`L9^ zvx(WtYhurxYMkv<@K3GXUQ080)vhZSE_^sAoPO%PRZ5(nt-~54j<9l8B_p$@)FbN8 z9y9$6Vhs6}Jxy`z(cApI`q8{1m)^@XtE{%S$ZxgyW3>N>3Lkq~qe*Okz$I}D_wOrJ zB&!#0xU|yU?TcrpDSJegSesAOF3l;YHgnvmJN-rS&Wn@tuDHHEG9g;+f0C2x+?}VT z;{$!?oObc?X!Lq1k3RP-h$@KK_jI~>=G-tBaR=pg{XfcI^qTZ#y82$v z-*A8XPwCff4lm@EXS0MITiU)zYlTzptTflk zH`cBcNeO$}ba0WE(Te}~_B2d!6J399`!}vH`>Ql9ie4T)zWi0Uz~jzWKZ@CA6zd*a zaOwX;)~I;;Uu&sXu^*k0$WvYPMbaaPu_^NSw%bo`3*)taXsefNh?;|Kn-I|csYY+Jg| zb~zT9|DFDK`;KWb%3Mu#Tf>#*X3rG3K5e@2)2M)_3+7g=X56XSxK)(jOVLfEUhna# zZin|w>IvDux3R5Wp0ww+Z~Lh*ul9o9^1Tk(9-$M&_Nyel@SAq-VUN0J67S7am%Ke^ zr+>J;KVSCOmV>L(gnrE2w(8(z=g%LDzk8*A-1JbP)^6k3g?}phH!VxL^GRh&RI*IV z$EwwA7O@XamY+Oy_50Lhc7<(T-4o;t%sl>RD7kzJI2_Bf_Kfnpqw>Gru5M55E?|6k ztj$(=?b|JHRL`}CmdRgd;pGKqJXNfo+?ceS#eHpNo%olA@X$S%j~Bdj&56iR z-|H}IYMOHO3q9Uvp{&K{IohUPa#DFUP0L$o;pE9ts=da}7OxJ*h&l4{bv)sU-}UZ* zZA9p!$hp@}pEr|KX4T%-E?x0=#=nlhJj<}QPlof-{~MkC9ivvgagCyK`L;6;GhAg7 z_su_l^sda@PZwJ{9kZ*ygoprn%--vF6uxBKK9F`0bI~I)Tya zyU-2)<;xTn_O4LOuX&>&dE)iK6`S4!d?{d6cwKbwt^7R3bH&(78SUd7e9 zG-*-zrJKeNzD#m)iCQRKw!G{piI^OFBRX_e8*FBhl3ZKY>n?n#3$zYk8VI(4YBIf>PZZU#Bb1n4{Wbe8tD~ z&-(Pet5)7I*=*f=bt=#6RqS6Lx5>!veLT6k`~!2NyrR~sYad;2PM>|g@X!Zkm;Umv z$uT)Gd*URXcHKH#%~TY6n1zpP=gO)!m;Gc@)$pIEeY;n`ywL>9_ST3^7f!?>=yUGQsF zq8WSQv_EU-XK6TUT-e94SxdQc{lOP@u1Vk8wp!0rG@5)m`rz)ITj^%oHnNt^TJxfp z{rsehY`2^vOTXGLU7#*tyQSp0h+3hEv}A**{}Ge#tSQs~yiz##%x7=to+k_6{#l%T zx9o%dgAW#xzrUTy6fozR(#zBJC8_S1Vd2&Cs`t!%TRT;Z< z?(=A;v*agB$uxwm)K%}F5?HGI^-#)g&Vro%LAxz>#O-=pth;ZE(M?w^#tF+8lpcG0 z;{OBNxvLrd6e_AUBIB;!X|;1*FD@Zn-C^Tj^N zYg1ap+;S(?E5|!6>|y*ayIyJc@e^-r_?LHo-6UVhWOOcn7oR~~ZQ;BFa@;$+`qQbff|+9R(&>*j&)N>bXZw z-1d9a!L5(xDs6B1{r2@$^9XZaedYWUzFr>28+ANBmh*^Bt^e3G>-(hAXSU9>CTQ{G zSl^kE=p5^)Sj?)r$JMH>;yvH_j=x`8${gpp}j%%*})_vmjq&H_m{JZL^c8G}l%bgo^W3tZYt_^G51bM5a0^%z~~ zY`a#ZMYV1EfA{{1*>&5@jHc;Mot*#j-~WI2PMom)xHrS}V(`r8@BMfZC(k}MrNckG zzjaZPq(s@F9IIUgl8)PAXRn$q#^!4u6Th85`pmYw>&!dPeM{qCB{<#F#n#V~U4Jc0 z;b&tT`>R3wE_~M6>7=r~#P2I>+GERG%RH0R)F!TW3H)NmJVBtEHzXk7%bhuM?0+wO zxA>=lx4lF7tB@`mxjx6UQ}#RYya_+U@;r^RX|3SNzs64MoNn)UA+0($N%M_sU=@>8 z&1>Hr&;Mm6(@rexWwpL-AM!>r^keu>dHY`nWcEMrlwQ8}sa{uyKF?2?JKy`7vUeZ0 z_$r@p(meWAYsqz$joUjMXY)TeCwRSP{`~B%F{{rqo^VZDu6pvzD_zPP+YCKH|&&3^Aup5w%#3Z;6E;-^}?PzUEq_s8zv_gt8UaB-gHe zy}8gvcW$)p^|1cJIhETNZ{8JYmaY+JEV^~hC-W~^hZ&A*I2>tI5`MIB(?;PAZaJ?r z(-~dm|F=H+&%?aCZG*JMzRC~T_1xkY`TeYY^77Nm%u0fj_vy26MIVHj-eA_# zMw_FqEp9n{h>0oPruk&h{9E0PQa%n`2UK*_e;n8Qq4(s&j3;~EMYD6uu*^$+#(j8q z>dbHPi=9k8H!1vhRl32RHRse%cH^^ucIaq2EoygsskD~&^^G1ytJh1Ncpph}pXuc- zyf4Z5<^LSd_cN<*x$Jy-wfl5~pw{_9SW2#Gb-aCq(OQDrVPjyRfk6TDI5o z3EGXFf)UJ;r8?3L`iyE5@;w%0B`xy59Cl5EcL$r9lS5gn%$w>X{J;O|%ktk@#eL8q zL%e=&s?+J9{#j-oHeU{2_Mhm-zj^KSIc8P0Mv1Q+SD8N(dOzWL?4JK$zio`T>%ETg zmyFbEhS~>*uCbl2JNy1&cKK83R~vdXpX;v9<9akD(d4rTBgZUuDWxruI>qi{^;X(j zEfl!#>djs--)HU|pY?gl4<@S3*I>MUwwLYN=UbJB1TByAI<#?zJ&EEw9j3Zdy6b*$ zSy!Bp^tlxWp3iYT!ftRRER2b_xJaLC?JoZF2OplyVV1kCwD;ov%>SuvW=u=@x+jJS zg|S`IJQ{xMs{WGBhtIP!ru^*K=6So}QRJfSZ*>2@y4IE{E1kL`_Bq~O>>9~fkhwBT zv}UbaV&~@efOw~Fjhp3(+y36m*mahP$NQ~`#DDQZ!Jhq19J9}yQQ72VYQpn{b7tYG zzh3G;eFJ^RryF??m)v7^XgZw4h;u3U8ikT-zn5cXpGbX1v$vk7xUH zZ__+ykBD+_1#_025sK;Gk`qF{v{@QhvB@O}9NogX=&Xc~fZUV*te$I!tDg63oWy66k{IygvfMYWr!{fQSSNj#;x5)bt;42Q zZR@k&|Fy@&izog&W^G8^`FO|oE7#kSD%z)aHGO8wW|-kOdqKhBKly)F7B2T$lwqr@ z({8F?+qHO$*Q}SV_ofL{wJ7O$H+1`)J$7eB}Px71jYX6r%jvprO>}XMxf4tx2GUx9l zt1I|omXze&zTd%f>X$mRyF%?1CC^Zq6mLWCzJfVIH&drJo{v7i{kgI0c{`Oo-FzP& z==ezrN3HI96~5owZtr&c$#K@|O1HOP+2*hyjB}IWE3Zw>9&1~zB4&D?O0{G$>wa|l z<>y<>aTgy?@p}KJHSLGT3!&9Fw7HD;{FdoA zt+>`MJ`((Xs`qma|4W}V3fHd+tH>-w|wP~OuzPJm92WM zvwfKqtFIr&T5kn`{A_Wb^^5vG`O2(XCd;fdS!IX)!3(XbpB&z^87)JO-1Om7 zIdkvF4ySAV=G|*&ema)U_myMn2IiIR{+WvuuUtKRB=$hXRt3r1UOHwr9sPnFd;XLa z-r;l)n6~21eH$Mq4JOt-XO>v>iTRv5$-4US*{+5WL1Td!B>L<>tMW?v8dWX74&*gJc> zvd3W_ZO0~s{|b&F4znfYzY0yB`{Pu0^#tp!Go}WubNc&h#;!wI5B^m+*)3Y9v*>`J z|2wuK_Qab82}fmge8a!lWM1N_b57osDj$Bs>#vXds~XMQ+#DTC#g=F}uFF=q^ZZ24 zxt=4!_m+7+UiVa`cVR|FbW+Rb2bcd$y|c%2jmz-Wy9&$2yGd+iF#5&n>8kDBdt zPln6=5!#V0VR3zReTZ+1vvq^qpN`}-n<$HP`N*vaYx3<+P0Y96mz`35j&JYBh8NG> zWAgZx2FGVcp1buWZ++yCp1t04_bK(MKRe(1>b`fxzdL_=&oFPEQ&PPracxG;Gpoo0 zzp^5O+nzdZ?bpArlF7uzbt-lm`};&I9|Pk(JC<9j%Wk=DbMV>kWR^=BjPH(L+nZ?r zbAonmmwVZ=_v#u>dsj^gp1g3UQNL{IlS7W5+25@<*8lm>a*DdQ`OJ(fX(nV1UD>+`QT6)>*{J+_(JsW)z9WE$^yk!*$;+uQg zbJcX!e~-s{5wJ{ct+Imj2T#noHLqm93xZ2|`^LoAH z=ON*ti*ioQH#Pn#U!}%mqsKk{b^l&1wF?(Szj?H)+Fa7Ve{X`?xq>;OW>+}c4gd4> zsonNyGwzntef}qH`4(Hp(kq!yHF&Q*E{!l-5w<(GJJI0j`YDqFk9kfn2~Vn@d;R6# zMAou*lMIzFtU04F-S>CkKhae?|D_*$DKp38McS!N23$2CK8LJW9Y1@1(hos~t!rPH z9?F%h*(b%|%`taE>@oiTe6RE0v>#*oy!H7q-&cp!q-$b-Tr@~bDQQ`2bx{A!Jc%g= z5upqz3oqyVdU=d@mTcYsYa17`^_hMC_jyIk-LL0oIm+#gy(6HxLBYD}=tRybd@@q} zKcDP8etos}-w@u1U6Fg)-M0D9PyYSJ`9kQG{Q~zFD#~&5n6N}%nlQ^fX2Q+a?w{&I z-dlZod31G_{wBNYGv@O>RVs`A{_!8@JY)LwaT z?0`tk>*n9O1{2@^Tf}!)lGVLZ!j1SZ~()U$rIj zeY(oL-RU0Fmy~{p|84K}GEcRFY1;B4zl|GTX~+16$gZ`VDip#LWwrE_pHkZX)81@t zBJq1Sdc4)QZH?Po@lxZfo{f0N(G$OZZB)#;Fyf&uDyl5Zd@gBDVda#0+Nj ztE(hzUWTy#sr!-sEcWHbB|&%C4wh;AfBw68mQSHh@7qQ4+wLFMxOtvK>HR_0y|xoO zer&n3Cg!U@y~9){q<_xZ3D@w zo+tN}uiNzFf&JI2e7ARd_SU&;e*0}$`RvIZ{WCqKX-$93-Jis4cUyX_`(E1A)pfd$ zFKqV>$Dn6&Gk|Xo@PgIe+W-x zUA(Q~gq8crtVj3$zPP%6)3a}!#!r%av@*8q?pyb1(-iSt5uK&?JBtq2uDf=7_fe@0 zqHApr?e+fpkx_2f)bmAEKO8e!To`5RCLWseVtzvD{=}aW6Llo=Y96+H%C!sCIP|CW z<0_Y)Y3Xb;<2g2dw0iPv{bYruS3O_y8}?K%Rp$9{dmP+oxM-Kk{8djmZ!KOd)qbv~ z@49x%5$4xFW6b6FTkkpvh)FFxaA>-H?KzL*5jMQyRZC{h5B6SY-*Nom9hU>bZ*KNz zg}?NeRj}f^!reJRY`^2SIVtoT74;uhCwxt)?r$nPwy#o9 zty$eROYqRr?W?bFA znf>m6R`ZZ+> z{o_lkZ-{aTv(~+KmB&})nq}umv8>gtoTmS=~xuYD9Vr=Me$I-hFN=FL z-vQlcIwzVhm>8Vx4%67FBK_~#CC1BB?boKQI4Kfev5M8x$|ff=&e$O^cx8{Kk@^wm z&7C#Dtj{~XEmSx7zA?vq>dI^VUw#-FnwaOS*54@;TYorw#kY)(%F7e1dL*uG_jWsB z*z<+?fYND2{iR{k^4UV#w}h@ zv)dXhaH=BU#+;-4;vTE^|6a-IC{kkboH@a)F8?ncjGL_4d@0%OpW$kK$8|fS7jES0xX^8%={M)^uY-@PUTr?_ z?D*No<&aUju=asDw~xxJpPwClvg}9Ye6CqCtD?^wzHIo$qsP$Dqg(A_%h|q8E77^} zf-i;Fw26n-h^)K(R9j|JULnWqtlRhdx!(DkN&T;yGd=D}N^o_b~3i0b3eEnViPIH+nyJmOtkoL`qBQ`(-<0OZ{K0E zMsiccL^dPEQy)_l^fup=JCeb_#A|tYM18`ERt+5{js+Ziat~XDx(h64W<1z!^!HxP z=XKv+d?~YheKw;gLpyN6mb@teEA+p(ZGU00`>_5>wkPc#>_7PHY#q2YckKD^<2GA0;Z&)@h2{j?4EuZGoX3y$`jo8hnsdC1zbk_dQS%G!icZs}XvF(<-bWt%q za=GEm?^RP*t#WuF&^G&mAhdo{MDL4kW1Jw?rC4{&Kb+aL>ms& z-0k0ZIaZFzYKwgQ%xLj*zSDK5B!_yt2)2JP@vUt9Ai1C6@`7nAY{k{@&dPklm^b~n z_N8@;W*GY!FF)UHETvnZJ0;Fa+tn&z0_W9*!vCze;LBJ%o`W1R(ZGrw6kAD&Yg^ydqkj8ANdbA?@i%7feWKb)>y zzJ1a2=I*V1u@V!OXh_f4dRLaSQ!uVLPfIv_y8iD^%bCC4IJZmdLmksuVaq4kS?n%q zHk+Ti9MTA?n$D#0Y}v`n&-;AZ#U_}x@jAwO9B^&_Cn3X_z|?e2>{Pz5hLy3z1lI-q z3;(mLc&!k1kDYvc;tVd9^{*JO6<(XrwC{+s>atCGu@bH`+a<#y^p2!&oS!%$XvxjO zVu5<$>h6Yy>19(48Qm-|b8O#fWyLt}u$a@7b|%lzGadgaI9yV?&A?>wq<Y?9{Lxn;zVqGMeHGD5%KZ8?8djM}GTqmH^KRvWUh$^g$4qut=FeNglX9y3 z%9{hbpUyt1sT@Cbs{6((H|G0Ho^+7c<5KaAZChd1ri?V7u9ptaPqA*@@m$GTPPM($ zL&o#Yl=&?dTlKoj_QnXfE7gZ)73k%4M*GCiHq7B_IpupHUSP@lxNFjecO2)Y%`P)` zlwbYd|IeldhnH4Q98N4Q`C{ZF@`Q`Q;ogZ&-~N`}GoQ)7>+Jt2y_;9hZQUiaN%)(9 z(2v_4kJuABSe*NF8bkOQyn~KD)am>?rG7;!!y^%)_Z>+u7b}>x@2F%?a8~=bypfIX zqS3#`&wYX^z3sL$oaOH)s_Zj}k`GbXCb3Ay=dSrLE8(eiyQi6DY+`t___wL*hDz&((h)Je%(=2vE%K^bGcjMKCo?6eVx?e#Assfyu5LruG0RU z!4kjkNJ%v(+__@-M*8mBM+MJ3FOL<6D zEi*dT!<{#&@7%J@v#$wFxas7y^D1}FkL;NfWutbaiu5>gXb2r$JGU?9^fs%2k9~5N zj&QAye^wV%#m|yFg>mQiH5MN#WZXBn?p~j>*~5$PLW5+*Rpp>_Hx4fCcp4qp!F4%n z&L6MdZEoLVzcdwR=A_?K-rBxM&HF=9tlX-(Iq9Xh91WbZIM|c_UH6?QXP>!i^U~_o ze%j{}&d&_a-00%|HMVr6`tP&1Rz(Pz_N@#1`(*l^_hN6poqA+a?9x&fy!o~qdGJ~4OMFUItU3^d^L5Y`6pP z{JeACRD7HGuRYmMR-EwOW4f*SoY{nlUw%9~YIN^ft>H9Yfea(@iArvAeMVQ-epUEU zoG!RNhG|}d^@X2u)5^r}d)D5_s$Oc!yu@3x>G`ucUe*HbO$Yz}I=|V#lVj7QqWO%H zW!H8#f2?@6UzKx(2Ghw!4?_aj6}X-|zM8uI)%8Oa+HTs$#*teMM5B^4O_zxr=`@sJ zs!(0U_4(Cdo6P^A`&Hfwhuv?Kp1l6}d^u06?S5I8o4P|MY5#a4CuZ~Wz%$vUKW~NK zxA9FYImR%h*R9pg{oX^)ms4wuCO>Fds-5Fqdot?Gp>OFwW*=yocuMcq)Q#uEj&@D` zzP_Yu)_)zFJ<`nrCs^O6@vV!!afUVPxy`R@i~1fPns!QlkI|cS0@* zRcn0nbv)`>DsC5lnDg#``5P$_PM$_xq5C&IwD0);#p6+`_U3PIx(Yu$iP#-D_w`}k z3u?@v%k*Z63kDQ;}7M99XBiHfDE?ri1)s~7r#gMMemQF@qYoya2 z`J{@+nCh}~az&)A*=6i;MKmHk;(M!s@cW7tdv*xvIh>j#HMcQEqhf&spH)KPtLOcV zzrV|?ugtyO_xk?p*E8)nvtE16oc8JWUKWQPDLy6dx9~+9-e&Vz`_3V@VCI&!^9+K& z&RcWT{PKcZyl>W<=xa}N+ZSEadVjt2=D>M^6>|gxuGsj`ayoL_x-ox+lZ<2C$5qE< zQ>&NB%qnb8`gB}od4^}doR!m#r@Y@WsXxyRgb8pyAo+#z}WxzIByR z*`ATj^oOPJ%+bRhw=*Zc`LJ?#gJ_<1+`IK$3Td9K*Q!^0JBqFgoFX^R%I5KpC4awv zp0O{!&%Eh9^QKkH=J9@6U2;7%?D{0z$vJly?#{Inc-Y;|$ocwB;8ca9*CXfKh*x{5 z%1zo-%d>OAZ2q>RA8JzB`|1=Od1})$&OK9~byDv7N_p4Ro*%OADs2UglPy!PUukqN z$^5o z;ML2yIx&BDd^10)cVc3`%#7{U*(-7y|6Mq{%-Xk@W!8_+FLNJEcqT2^am&~+;d5G= zNYVL-cSgO>Pn&PuE~2tz!xo?X`8W5!%vsM^Xfq>n_QA({@9m$rC?WP5tFZ8~z3cB4 zX~#4NyZ4+wb!LKIn|^`W_od4Oa}uW?dUEj2-X%*G7H>O}xpnnjQ!(}OC9HD0HoP_P z$eS}W%1C1F7XQ!Fw}=}sU+QoFdSC%#?raM+R;8zd@Z~|B}ew{?vr;{H2xlJ#Ci6)ZV<=#fbE&lKBj8T#_(i7TS-pHNiH+PigmTVq(% zWZ!xv+fWGu@v?xUnnk;oXzE?KEPq`kt*$)4+v&Y2=Ra8nVMeV&0W&TE#w7(Oa^FbD z{n%)6$2PY28^7JFSrffVdFqekz2fq|^M&p6$yF+!BR>2}TB=fZzW1F^+P;`VXNjHL zZ>S#C>(0E)dNLyV#{KfkdXLo)`rex+c393PltnIRLi$hbd)x}<`-H+9b^bm6ud*WT zYh#Mf4WqD*%$pnk)*t|KTD@AwUk=$PrP1anxt3Lm$QG&jH`q92mG4mAUrc) z*lA|5%_rrJEn=7C0|X3?K0aSpJDpkb&lk0I+mE$feYrtuU%AI-Q&WREqGtEr$jZKX zB$?Ufmg+U*#HO>nbvH~eW!BBzHue?IJ>gx7Aa$%pwrY+2Tw z;C$-h7IVq?uBjtRLZ=LecEAB{_^%zmQ7iuXC|$hEHG>PuM64lE`DCI?Px$z zlHj2Y4(D>6)*Wno^HK5+lbg=7|4a-`_ttscp3l#w(UV~i{_f!G>TPdMwDO+6Qr{w} zF^6eto`aaWV~Fx;J_s~b{&(n=_}{r%=*wRIex-?U7pb#8y<#&u33%`Z%G=K|rqXtVM8{SA(Mjvvq(|_w=cf&m1<)5ccD&?S0zxHFZ;!ejMi^{hS+9 z*Qm`3v?y!!{qyym$Je;8k2|^453YG&|2O>AyElp-qNP8te!6?=gtQ1LvCZFCPy05h znNxjo^G%EMe-qNm-+cHMCdzWHPvv>@|HqC?&IBg~u}v3=jtk)xs(WP_rT>;ocF9Hy zzvpx2Ff#pH9=ze8|L#u^va9|GKYs537})6}|ih%adLAjMm6)_?pmgu4LM} z%Yq#jl`M=MZ6=#Gg{Or!E0?R3K2|DU>6|WAw&HwU+gqa&{rPU=Mem}ma~z&Me(U>CZQJU%H(Q@yw3^i<>Y?K{eZj=QN>-m-f3amti{t)h zrLEr7@hy0B@`3#0BA-rP+k5s5n_!RIw69a{Z{F}&M&`Pb&4e41uWdM2=Jd`{+|KFZ z$5~-Kb(ZStk8=IDhkN&F{+agS;f?)9g~dEwx78*^wdMa{`juy~T_Nl5w+~Tf?z;+p zui-2S6=Dm^dv`|TS5yDB*^#s7iu1@#F4aAwe{#d|d((bjz3=^_j8oxev5aqh$E%Xb z56s@JsH;3_Aas9@#$Ud&UbjkG zy@F%L?5g8C7Pzg5a#;L&dD^}=U%&sErY@eIqOnnR(mGB~wl{~aZ{`1Rc+>Wpz6iF8 z=8i2t=Hx!;cH1`j(ZsZV?TRM%{yUeYPk7ALu0AxSJ9s$12BIq%CK zF`Zw<(0g{Ym&SpCh$0PkcZ8FwxJ*DoGC;C*@Hx0LF~w;n$WS8niSTEI0sbiZ`ES^2!5-~NTS z{7;n@>JHm`U*{CxJ^wr5i~h!I@w0q2sHwfQhI#*!_?=ZLekYzTnilvXrn#xQ(#|@4 zd3xU#{+dzi;2X-EoP3@ubq#OFi}5U9&~6c1Rsd(+ij* zm?RVRD*3eHtqBY|%3-k_{3365EnQz)AsjLFRdnhkPPN=^Ve>jQcjm8Odr;HY{b4tp-*HD`{|oE@gRDd3Nm`lOwFOTL~wtK!c4 z=ZaINiP5hOlTFk00vNcH?w(dE`;a)*!|8m*DkD8U?Z_M5PNEtc*jBGsNS)T&&307$ zy++GKu`Tb6L|#Owb|2-Q)*i0g!8e`Pk~hiVUrBQ{yF+8l23F0ze&4QaKELj7Vb;AZ z-YeV6IAyN#EVg*M$@9BV#w*Dg!n@u0HpO`tJ8s08Ve_$+a@RV`u!ZIZ>|?Ka|J?kJ}_PLl34$>exK@!C66y|Js`QG^nalE0rA&0 z&dYam&N<>gQ(Eto@#lUR0>Nzimn^hl9(uH`m|1UsWCb*fRC@Lc7Cv^@Atun^m>^ zT6kmai&OrBG1*!1ZQV(IrDue{wU_j89Wb=@Keb)Vg)7U(Y`LJ$sTXe)e4;l9N-$~W zJE>bKD{QvWkajx4{DU!Y|A(m@9>qTyBU0;KwAJn@T+30b(v7$$_UXtRah~Zjj%WYm zaa?|Q8TVWZ=E`jTY1$Y6wHFT1&}2)&4Nb#!S9pHi3OV7*WSvtYUAMK) zXhPHJL-z&l__=jj>~tt?`!4pqYe6z!%zb4&E=NFQkbn&C;MY$l|sSNu9gC{DU_~2^fqhK08_$E1qZGxTEs;!F0irt?TYFTsq0sRua6aS6;_3;@IZJDjWY? z2oe{r3C-|bRDOclb5)?y)K`ZepZaoW8yDM&%M%hqBYZ!nY}$XaesV{L#ERFS-MSnF zsx)4_bnbN1`S#9QD)^$}(a@FWei&~tyLu%1pUUa;(~HFNB^<7OTJs?#qhimx>)-5c z>O|*#dpldZrM~B1-oF=VneGou+T$E+R{vSO@9+0nt81Tr?o4;s9_6E{e{Jy|{#^op zgxI-_JKqP*bo)`W<g6Rm*&Q zUSG``qcy+2c*y(DNZ4po8|CO2d-Y?+%b19y?7WHJmKt`jIxoH7d9tgD`)am*&TO_{ zcdslB_`TXFEb8!?sG{`;6nj5r$T#*R#fN-c(_S%SQ|VIE&8^Z`^1tOxdhpKb;sX75 z*_$Klif(P;`gm5dF~Mx>lGX;N+?$O4rSYG6PV#NKt-%wVaDVUlipAf|Wm)ICx5rLf zu+a8FhfJRM=P#yqM>!6(^|(Ffxw!D||JfbKBptUGCVW$#Yv{8lPo^UCOEzDc>L;aZ zqI%bjtMZJ?oPNh#lN`jwawOF{rcO8DB3*OuxR z)_cs!*sXkIKbKHI<=sc>{z{$Qe9}**t}phxv0D8|!~EwHZk?5Vq-V}He};uaL$_;u zPcYwU(;KfA&fFd)y85%+$E#1X>dRKOJg(7vb#Kq?vhtPImyR-@u{zgWD4>~j()*jy zxpR#o49u!O6!$%PSARdYS^SCd+2^wD)~8krn|a<(nK|2jpTN_yXO71#-MOqv4=)fY znztx!$;yQs#*6L*-tk{<-jjIY(M-L_Q*sTht9u{LYtA|KM*5gv;bWGZ9fIYdM!~aV z7(V=G+PTSU$>wEm=gXEbn7K$jXE0sDH#I6={NLxKBNjRjk6oCQXVLrkzz3NFk57xs zfB0{|DZxzKskq_$6`{Eu=dBGwx=yZH8I_Uae|ZPTO#ueBIf?(enFOZRt}0X99$4zq zlEA7}Rdue;cjohF!I9Z+MjKBg+ka&+);SdWx7I`Nk7%Nf%a!!oi#S{~-w15l$;p^5 z>iOa4EN;WE1;6uOT@wzlNpW+w&D_$ywDFaEk=h3H51afKgy+O3PX4FjpndG)V$%Zk zdsjS^)&##uxcQXn6u0r5YPD}`SC;mRi*`(ExO7!1mhoYOv)a0p0>)!sD?;aYc*hCY zGY1^A?UG9G77rmyVOs`!+XKdc|g!e+n z`b;UuPj>d9lN!w)?{&ODtcPQ`H{#G-#>datMfKoRrXsb z5%qevpvLd3Zv;A?I|*DC^s?czxu7FY{ytb$8en5OVgEmk0D<7#$EFTCw(W^q7&)xY z-C4Y~qFN(u?NhaNYJXZe!VU#YtvnM^@_3g()}>rsDwJKD8JWA~lM2L1X4d#1EMkBD0=-mbr33(h+{iagtU3CJuWsr}g_N?ooTf{rdC6C*ij~zor|UKU zdTFH>n`0$s5&nJt`c#z{Yx6oCeqJj#PTT*IVYhVUulq+Q*||S4yRrJ~Zngd%@yc_QZGBi??*@eV?{Y{`~Wlj&Re4wm@geKPoSuI%wYPswxXu zvQ)h#H?LKmL*W2BWA3FN`#&`%+IwdH*U7y8;#&J3$L8LJ5)aH@OHJXFN<7q>bd<+4 zGwVc2Mc0%s`a8K9Co(zh4tuJA)Gfh1$cd-9E&?CZS@3hC?>GJk+hdH8O)V=(UoqeyJFQj8|CGynM+;=kR zr$nN}PqSB=ZCcLs%f|BBgKL+61T=8vY=+@aF9D zy>qfuEw<||o$^0Rg}3zgOYZbtcUr>rBq}{e|!AqU5gL+c>Ga-C%~b=mfD~DaDAR{Ra{%LtUb! zw+2rz=B+uCV)=<_W3S1tYO7>F>uU;Iqx{#%hnx;}DxF`g$N2n-OGVvt_cP5JwgsEt zoJeI=xp(9AF4K> z{9_3Uou7Ks$s+9h;>O%lYR5myZez`5#_~eIza&IZ~1mV7P{eZ)PH|A|HmE_xJJLPGhr(l(Y^EsY>q9<}% zqN9TSPI+)#@vn-k&E}VnoD#suY5m!dzk1=lG_D<|@8%sly+g*Y&v(n*m!032hCO<} zygud|#hp2vi|?EB%GUUY)XbLO2|zb$8fXf3OK z*I!qBqwdZ3?ERSsbaHLY=081m$Rf97#*UrK3eV2b4X<9Ka?X#(;mso6pxF-Q-?kRZ z|ESyDxy}FI^vBgwQ#a0h9&@MS)eZYP`OxgdHEX_q*_6^<7pIW%pXcggZbiFozc?Sh z^ea_6|M<<7(*K&9%>!zB^D?}7nE7U!EWT`JYa)APYpH|6{sSBTR7cz{FZ!hB(V^q^ z{4qIdrvG*PQ+{kU1B z@9e7=ar;H)Ofo%P6fr+l_Ql0|_vo~r7N42LX71A~t1jNhvo~11JYm|q>6Zkxczk`! z81Fr;IUsyLzclW3*{TM8C+|z{mT%Xzx`oVV5lXB0>Tu$^U;Qepn^|Iiq^-6c`D5H3 zw0!T{`M(9acP7mab)C;U>EFuUJ+F!b0_NSV^Y@V#pBCAAAgBGx>n|I5eJ(HDRk?8M zbGd-tdpi$YT~MXIs%ZVQiAOcJE#25xkn#D7nWW?MiZj!jfVmj`f599jMlcHUEhC6%iA~Dq&Q`wq+F1VL6xmh`L zy5;jLtD-8oU#cljRJ^)XZToZONw1a*sTq2hzNy|W=pABlP|>jQ(-ZZjmrneg=5}_& zj63^FYos!5C#8O_>~>)5z3HcLr}FG30q@EZrAJ)V#;$*sUyF|qPG0O9_Nl!+VD9EK z<$e1T%I@ZJ7cu4W~+EaJAZ-{?;!jPujFT70hgkqLZUx?xy-Zhh^Xp6W0nO_}j z@&4qZ*lvE-@2f51I>qI=kJl}*WLvdMf5o{XOW%CEleV$x>8lKb9yd+QxF+>{>AYid zig0ihjnruUd|=d>(6o!#n9~ zZzD9zHfh+#ObQO(_~^^B69*RVl}lUqX;aj{Blf!@CU_`aE-!X+JoUgUdP6~zSk{yy zVKbk&ueG%E^L}dBV{%H+FL|E#jP)(c&fl`$`nFMi-fm|GuD6q3F$<}DOHa?)bT_n& zd4_I_Prb>q3eR~5jykvgWZaXqF1);&hdq4usiPt{E=k?n*16Dj!eTL}nzeJZCRoq7 zd~41#`vBiGx!5@MT}Cd-PrrVB!Zm41pX}_PavwVC3;udB zH|L2pPq93>@M_WP$MZs4UO4`h-PWOP-S*+p^!ZLJlx!l;|7Nw}TG4Eg&-c`$&14X&pD)+hk zVwqK&Z!8yd6@2F2+!3V|vNL9Rox`Oy9a&x+pM@qE%he%2FqV!Jrm`_ zh1CKt^znQTj6B=8tU-vUvS7yCSlgpN-Om4f5*PL~?nGp)COhxJ_Nc$Bvwkzo+x;N# z%@qAt)A;gtUS7PoBW3Y^^Ua%mxb`~ViP8Hz{lUWWZ;Q@Z9O~J4_Izv; zZNeHhJ_uT|qdfZdL>?Axy+cRMU$A5r$ameXJW*R^e*3ywL+#qj+y9@}b1)6ryXl}< znYW(UmPfM||2rnPrx!dNXwHjk#RlSm8 z$EJb>!C_No3Ll%4r1!P{*;KRLzS9|h-05g_ieAGmcl*qyxWqr7o3t9Q9S(i#bhVV{ zXWt?H%R$WYt)Cy<=R0D&LvdF0Z+VbZD{EVP;;K^ko4R8 z=OecjbH8n1J6Qbii|w0l{LfZ=TaqE;Up@6QQ<%=vToK=PA(p*5k_SFL-{d~uO03c; zI%|LUn&Zx?0_8kvuV#jE{$lxPsO@v#J(N8q`p$zR^9Tv#`bc!jJ9ur@8DtW&fnZ)o)Q)zY#eSLEoqTIjLl!X>-m1wpJpZNQQ1|mkv!90ME;y9* zKg#%H`lA=I{_Uqfn;hJyeM!?xuHk6whUN*3)hbthS6=rM4=g)rxmB`yLp z&WL}JGJRSR>3MeMM_-dOCqq0gT(I)H`b{8r^Mh?#CKsejmZv;dH0&w*QmSE?_hN6C zcJL!lNyY_Q+$9h81&Qq1r|h)w8_=>x0;D0%xMq{OHDRzg&mPK=tO zpW0<5L7f>BpEgX13Y@wi@SgsoPpAAYzfxz6c{SyhMC^u%n)Y8@f7re$tiAS9vgqps zt_22?p42=|A;88k~aT$?@^T9 zkwsF8d?}_3@-a_BCbxZDaZvF8f$!!ImNY!#GQVGxAy+ILF!S^3!bL7|lXxFpys04Y zPORH7akKZ&hL0_u=A1R3TeYcC*0Xp@?ib!#CtusP2{M}l?7TBR{xsXk%9L+&O^biB zN5}kKZptzR_oSJGUUO$nQfBUU*PG?ln7!#}yqWg2;`$wHzZZ+Yq{Og zWeX>4F+Hd~HKJc;k?W44?Yepun$LF6*59rc(I=yv?%=iKy%F=GJ+EB5a~CA^FrO9g>O#BP5AdmE>c}Nwrm!s$;&+( zwoI^|_Qkfz?baWz@^AUQO$P6!)BL-48u#2gB_$*?eQDNrQ~Aw($JGvs@mtD78r-SW z{v%wlc=I~PH|w?Am*t92=ToXM>`zzM<7j+;b=oqRuW_luk#v3L9L znw|Oh`SF26$_@!`+|EEhs?@evwg4T2c0RO z*r#0Tce-fJ=T%83WDi+xHA`xJVX@aRODru$cGt#x|F*7;^osuH?&3aoS)Pu$cgfd) zT^m;jrEb-!s@vYiq8a_c_hE$?gA^Y!pdy*KB{ zhb!k!T&tT@ZMH$tI&!v|`r2oz;kE3|o`<(z$aO5LxZo0*_?-6~e@gq^_trMDiPA|n zFCAGtnVXM%SsZdtoy_p=xxwoA8c<4g?^gGLJd*dhO zOuZi2lKw{Oh`zxjUH!vL-kz}f!2FgWEG2eJ#-@eWqZdc4KPah@xSJ`<|Z>yQj`FEM_mle3TH_i%g6R*llniD$pJl8g@HTSX;V&@n}zO&MkH9ul> z{=1-a$wcuCIb%UaZ-hmGcq2`y;pYm-xS8DWk-a?~>kyjbmd{swwKR>9RhCE>+G5P<9sj#QG${jf6c$DGAlDu># zxlgW_r{1^X5W340@v`LLPmABb_U_)kd%kR(Vslru<4>;pw+~1ER%x~p|FQYj!8ec9 zR3EC8p8gQG;6S$iy2=FYbDx`zls@^gc0ux)7NyX#)9KUFsIb9oMT$(J9T8L9JJgn%sP%<@J0ozsf$T)gC%53%1GydL(}fTQNQEwct6Gu&8!t;~lPM*MC@h?bcqa z#H&0ZY?jNjL&i#zHB>*C3S~#RoUl)La^9Wx+ zr^O2%2~F%gW4z|i1*M4KzUr0hYwj`_*v_1GYQybg>wC97`T9d`?-mY^o8^x~7cVf=YHgqt&R1k&6mb*JEmv1F!YF$mT^{VT$K9l z)i0tsV#LEIMjUT2iYm<+PD*uE2OWQhDNk!=L-U|5qbH$|gINrMsw&IsL3Z8Pf zs59-_zGk7{TQjdGGk)BdGShC!=g6i9+kToJ-zl+a6Uztj;ue?S6+5;sWAS-(VZFWB>o@t=HN4mhHW)>OsMj z6VJ^8(%!x4nYzbwm+vFJ1GODyJZs9CCEYv2)+hbeT6|4IbEE!*f0ECS1z+)V412p- zWee-nIbyGW>UYX|vd@xud|Uad8e;{kd&arg!};5kzo>4Qdb#`QgYxfBZ*@83ic21j z_;7HVuki<-lexmzH!ODD|L~H}?;q9IZcKg3v#xI^^Et*)yT1*r^^@2CvwrV$^+mY# zH}lwU6I;X*nYbz{|MlYHh!-)U}nyK7E>&+kw1 zma@O61$>=r+LvKn;AF>N9(G+{x{c4{tSg7Rm&{JNH~jC`J~*h$^C~>pE$UnAw1o=$ ze@WLaU6d*x-k@=G`j`B}uRogXn6>JhxoFgK<-prT++nJR{(Q|&v*%l+Ir*4Raa`ix z&Bi=$ejUBM>QA8K6IZ?K_qV^^2+e7X# zxp4bs8Kl;l9hTgAMQ7P*^F2?$|6ik+eIdvxjrX!bnq&X%3)_Tp%$El3J!t&mPMMR( z>i=B5T??7dFPyi2%`~x3n}R2mFFzIKpLd6C;j{47?=~ONGMyzj)oI^ztLJ^)3j3AL z-FO<^CShx7Tc|54`1tJM+-vzy`ZsjF%MV|Bv_4^8_MfsD;{X3#;r4jGYhO^vALe(W zfAd~86vqgbYcRR*o1+zKZZhH1^oOzu4ZR<06BYi()rYQGxtBG^ThQ?3?a~)pOg0~? z5woAorhodknDc{&|NcnI9&PUC)nVsKXZz0HKVj>#s*Rb=tn6l9K>?PV3ZxhQ7kuH# z)c@sV;^S@4rfV1d%FVu8@vr=XTENM+Uz1lAUkVQXeg3mar`*P)2Ie&1C=nGkmAQ1M2?PL26n8*5KJcxZF`bo=Uif2N+V zx#uyVV13ouu+AkRziq2}^j6N=boRmSH%rW?oJ+A;_~FLo>gmVT6b~%<_9wIWicaHb z)%MvmUi|wBBl%-2wgoR|ZMlC#_`=kCNiy3XzFQrnE1VMPq%q?IA5)E@#iesMY|ZC) zvC2I8uz$_rZ3>M3qxHZR?;oMlHp6|Fu$$>DUboa?Q78}iJz|26-Wo8UR0UEHS3mTL}k z#$4_R(Qi%(84AC@FSJwg<;Rly6;3ma;(2o;!$Vgm9-FZD3XAfr-kLkb^JP{kRo4Dj z4~^K8ouVLKyF`Oc=FR2z+x$CsWb@sqTiXBU_(Y>0=NQU=|LA)(>Cw-0jr(3Z*4MPm z<&QYB<Z~ytyQ&N zrhHuHro$uIlBy0aL(C{+ce(HQ>jdnJULxkbmh#y zRSx|&XI8ZZyGVrJaCp!E(mu|PWske%s~3H4_m(_-{@-PvhQ{@Zq_6$57a6tJ_8tA* zf6@8T!rd1(b)K80loM6vX)wpoTSn({t7x6SPFbd>TmSPFte;ziy?GWdyceLy;wGTX zF1%Pj=55tK!hh?E%wPE4kg>NSIY1!LBVt*`}Cn_xbcr7LN z^CQ)>j^|cC2#wl*Uh-;0fy{}dvtdmFS06|Fr?)SOvySS|mAdP>Y1c1J^Evvv5`T7i zod~!gXz(y}Pv!%YT}mtOXkQn9v|@u~l$FlJ&DXwHUA*_%OZCnUAq!`t`efhp*DK~+ z_i312#vjdSp75(<^7`lDhGIW%9m%VFV7TOeza!tB)2d-*)i!KVr)mXS(-^$&TG>ZB zd+?VQW^Y`oyV^PS-K!+4mYk+LJ#3xV|4x?dKlm$u@{*!o=Ffli&-Dzo=IlB>dr{wq zHCuL=>iEoAx$gXoU5Z6!D}=p&#Z9{W>ENToRl>=anXTVn*d_mVpPL8Uj2FMP4X4~) zuG+PgH*eHG553bCI;rBlYQWbe?t7#Q?)@)!I>%*uPxDfM z-~I%9p`{;m4fft)a`t}2y*+3%lf2s0i_!Z^@4jBp^Tg|^1dp9mtHC|#V^@AfFve~7 zP!RlV_0Q4#>BYaz4g70n9r&}&-sW$(ri1Di``^zOCa>81JcaQ$^X7Fep5OG6gv5fH z^6z)lan{9E&0YVdBwb}en#M$O1T*_#E<+)8l`MIiK!&HHJ?xqe6wVSW( z4z4MjXtev1>5bNne$N%-MI^O)7VlnBa=XK-f1|-+t<3)+_w%HsKkP5dTip2L$K`hd zZ40!8Zr!nTtkr1u@_JWtOzF9v_=Yc;XQ$+8w{sbszQ@}jQ5;_UIWyJLEbBpY*Drbb z(m9JAJD9`1Ctlq${aU^$LtWE;&l9=7BAtR|SHGCHE-f70kBn`#a(Cyp8=o zlm9G=n7s9V>CVgoSBL4H*YZ|=%t)*FWv}m_qY(BYBtlH(ql4n7+r7tD=Wh5IH@RRo zSMBzePUDt8d){t7))1s#*t|`qtZ&_hZ}q>OMc1tm5=wo{ur4?x`(*IKwM!Vc<+A^_ zkS)Blu=|Ux@3PV_Sv|cv2`*0+!arvz_9P}%nuMR+V>k2RuWw2F$}ecxmUF4y`nkvF zpXB`uEOpOTpHprN_;W=4Qg%p(gn|Tn{C2r@IqqS9HD}q!SkfaGd-oTfyMKLDYCMc|+?3_2TkcO^a)zt$kHo%32hN}I zS@fujc|Ei8@^v1r#>@0Sa9!G>T|TMyNyihrr7X8^f3>cWkT3qV>~&W`!s~_&KOG}4 ze$vglr+e|~u_?YPC-Y^Lr^T3Tdze)H&bfK=#U%^s3fUicvxFw59cG%dB`sxo_xD}O z5ATO1Crq8V@1acayGPS)7DNOTD-~ug`Zd$^*CuU4>C&2sN3-{w?vPu}1bXo0*A<-{z*XhD(*noTY(kTUXC@YyPJUdMNi;j{yt zTnz7va?Q^Q-Zs6pyDZ&%MqJ?!?xy?O&Ukm|*G0X2EFe+;^4Ju{Z3~^d0-Y9z8iud` ztQY%5NakQ;A77%by6qRcYdb@WKK8EX`*SVv^Mt$X7lcY<{9m3DxxeQ$_sOP&O;M^d z(-wMOt34^|nD?xsbK4XiyEE^v7ysj8-?FodXG%@Lzm5R5hF*!4Tk{&9b(CKD_kQIb zkvHc&IWp>JKi5p^=@1Zoe_iCo_Iq=$_GDd+exYd=)%$5uq;_=Xx**Pmbd!a=KaV}F z%R1~RKRAZ;5H&5()E3|`sf_<0x-yh7=_iZ?l|2y(^ zt!p|*DTu0llwzUMSH*7&42*8 zEAi4N*R{RE@R=MujzN~rY;~sToXg=>e+*UEwUA$xEi)_ZidAjEki;op< zU7+OIH~)dzp3+<42lwy4?vnO%Mqug8g4t2mB0ld;2>xN;awdL;&Q_lIqPAnxn)^SB z2zFZVCa#dU|1rJyQdwycXGdR3&`d)n3S>oy1FjnK>MORYX z_!b#&sP;X2Zkfj>@%;YP#Ygs-U(eObfBP|s!M3HPtD`ckqED(se(Px!eUIH{+b-PB z*&XyaIPTP*17hKGf9R<-$=#i`jYA>2qD=W3pKE@bkWSC`2F8s_jk{mBOP^85wKR`B zYwB86IB(jcL+A9jnk-Q{q{hDBmEYkhi*7G5Xq#bF@%hQ;CtqA6=ASeUpSZ4Ddhdp# z*Tr(2qdQ+bKX)-}53ARjw8_q=)t6p;;^AQEB=GE!f}6m_;Ln-;vA3goJT6W-yJQb* zukS1A&mn7g`ve(NwoQ=BUUpnWBrw^bewCibqDtTOkMF-Ql{?)RE9f@U{w%wZ)W-e2 zJ0?ZEO~@+s%$8BkpQU|VYNwe={=<%1x$PUx`1e|hoLiCf%vJCI1KFRxmZpOJ@9+JR zob$G?>Vv|SYFC$|cdtI?3SO2r|6>Nn=Z*y4s?R%q*3XgM@N9QL z^r5a3_U`?W>z*n_9xLnewLr(2Bj^DO( zb@IIRJ@A03*IM24%WKV+&XZiNXRp31OHukCbWclYuSv+?ty0eevsrenk>7jO;ic#l zgCik~|2(Q+x)*&7-giaNU3lXe)@;ueR{d9X&unRM(9qb&!B%|za9Wwa>cZ!{)Q>*Z z;jO>>`^BVJmTj$jtKXVDm)jpzQz0`k)~}-C`|oXOuWz%TQDv`~HLEjta^>~KuVP$f zkJMKuhfjF$jMpkKR_n5|jnQAZ{xg?Z4c2>X-}UWu&lAa2$x$06wnt~(e#);Sw10K? z42H>S@zYeQe{R0y`DSWFy&*&OyPn?<}YIp=PCR4}3J zusZK&OZ&UpKc`|4*+^KIELR z-+R|5Uju$Cb-v9@YCpWxZ~OD^{K8#ouJ2q{pOi1&e&BKI%43JKDwNNb?SA}SjOU@% z?xZDh;mxiSIdo=~u3S~#bKy@U@9xR0iqDHTs4c5e`_NmN8l@9BMUpRs(c@3Rwk-eu zD`s9lyw)ge@k_qIjsTIfeb0X#NRt#_d^;oKzC|>1{O9nHOSOuJOA>8)PMuHYc(q6A z*SQ;c3$8@nz2|e&cjp8>b&=f$Yo&jj?z(QgkoTQt#$t36|-i; z-~X?(qrwWVZi$tCJ>^_v;U06#jaQ#L|1(c{$eG|Sq*4+4LhJlG9|0!WH{_gyl^9ALePOWvTH?NPFJX{VxuRcNr?2YrgVf z>FxQaMZ#(h-SjUqFk1KJ{GaJZ=J`c$ww`Lq%6X0B(9&C;+oy^h-{Y%z^G(xZy9{@Hu;l6xU_O;dR57Hu}2XDs^5K(B%Kp8vUX zhwd`GjFZg}SFl?7XyVjG2`=GhZLVc*QB(MR*5Kai{{;&!UsyJK%6oA)Ezo}B=dJ_Uj5B7Z?!M`js=CaoS!qvDe(-~o8_Dk%-Y=|w`+Vj~K|!DI zDc*I-Zk>DgWqBQBpYf$j^>lE>!S?O3AAiVsG^O5p-o53iwvPYW!{H0dD>zPdN!^=p zwO(oKQr7#2vUkrC>N{Y(Y~l6w%(mQ1wU2DzI3mhhyyBB`u*m$idb?~cXrFuFE&uA@ zpZ;Lq-9;zozAd`NdgjR1yYFsa|GE59^__1`-1F9yU7Nq{&T-G#$#PcTqFgn56E7{1 zRAg?f73gu^az6c)&vM&Ck6SL?Dc{__;mG^Y$uU7MjK#GDBzM$qIM|}H*p;QK?EbME zDsQ!wSz1{=C!ATh(|e_W^Hi<%7Xn@S&Ru_I6Kt^W&-C(5H{Siy*1xm)yr1^8mYAnY z82|d~*nRuRl({&|*zeTU8!D=c-7Gkd8A8)Z+7U(ae1 z7W%p3sZWHR{r>09r@osWKD_^+Ay)uhuxOu=Qj%CuGm{006;(hmmo zUCiF7#30!@H^NxE*TGC&zj1YCRlkH}txa|MiFw_Z?*4pZcY4O$eTLydpO+P?1hoj> zzPhq#=e4W%6X)7lFrMN4{&m@N-Gz2Ol8>r3M4vddHXuDYRqX!V!nZdw?;dVh+o%29 zTrYm5ZG73`Y#*yQdkg8A@A=r~oO}2BakTNyGYe9=wyoG=vENZI>bW1I+?22!c9zAW zymy!0)-Ox5@?$*z`PaI()hU}oeAx5Z*L_)d@m6idmEz{GX9;yDEPi|LGThW*=GYio z92R!ll)aDh3!qgSh z-$~kR_{X`C>5tx-U^k!dXA-o8?WR?WmwBu_aQvIA^z`>04aqTy!p9E1UXX60bN|dr zmk7Q8w;g<1-v6IA=k&paBF$%C&+aWNQ|9j|I(K8|UbEB1_D+9ZpAUlCt1Djj^-)Hm~0?i7bD z@`o08n|^;A9{*{>mrh5wCyC;+Z5Psv<1{9_?^stQvGas+dg7HctB&~JT$0vvQpmI6 z?s~6=Mdylll#jmmA3itmag^XL3O^Oyk?C&>&a)z5Oe!zW++L zUovre*IEUQ%>fLL+Z89dm1;fv)?fH)KZ|_p`8i>CI`#FMe9Oh(^I!DXlAn0^>ofB( z=6<1><}@%?Lp_xsr$vH6-+Xdt5jR3Kd|Pw5*$}wnJE)` zQ#zxlqyGP=x3|`Rp1os(aF*uATi4#1-&!2i_WZVS&&~8C{v}thFL?cIs_}8J!+RYL zpE?oqbeWBE@{&?p^{rQ81NYRfc4zKONZrnr*hhgga+K z{7i~67iY3>xX5hYk+E6i!Sc_Yy+-ldXRo@z!eS=Y6JTn#Pq85vNFx@J5tZEVgGZ}E)Jmv{`6&^)M`to#hg5* zd%-K9=%uu^oS2k~>xVht!xu~aKB%B{f=N8ul8Il!H&QG$|M}x*rkz(#2#2KY+*|w9 zQLpm-k$oP)a|7ffCh4xyeIXcdaY68tLu^7OZvAuk-bh$)exe?6=k1?L!P>y<)r_)N ze@Yhb^eWmF;ikjgP*-uybED0+lUti6t!Xfw$?dA_;=ok;@!j|%Jw5?pZ$wntRpR`a z^Ge~}vHLbDZN7a!_$F^*pZBJ!=~{Sqq ztESxBVY9aC)UDQ!KbaE$e2XxXI=sVa(Tc-SwuLJz(^-;xl)GGXHudzH1zRUS{c{A)5#Z{8up6{`)F9ZgD! z`ndVhL;K@CdG{+1YVps0Sio~YrY`^NnckDyxr=yz=kIpr^*r!3*<^nQxVwMSovE7VUT(bSZfWfE>E}O1KYpv*DZekdT~1)T>%Xrha)XHW*7bYU zXSbSFU(wj{J&VanLHK2Jqi<8u&KXt@=C)fViZIyfE}YTin!@nbBfaLzuB+$oL~mx_ z+w!z3`bS3QlEwOei$!Msd4FKmGcH&AA{C}o{T&~;maKT#cq_O69!L7a=@aL?be?^8 zwZqe&>^dAp@A(^}n#IdKgg(sOp)Z{Ar~k*bwdQM5mR#0SJU=ORN9MN|>$=utiJU2^ zlwUaQ$8F0=oIP$!Ta`8(y!8LY@1Ga0^U1ICU;ejE>((KQ$e@dg zbDchHmbo9z8N0N2Qe0&J>z#a?%=b5(72Dd{9kP0+mg|0|&PK&|A3A0()i#QmzU@il zG{+ase=Dq6XP&W7lM0vEA2|D?*y{eZH=a&(iQ#>2e0uSh(!xibN*h$U!lp#Xoce6~ zXwRV zICpNB!L{#u{uC^^tam$)-TQjgq|a8ibEe07D9g5G)PI}1YW7^1ZCfcifrP=W^(@a;rk!>=iGrF1r3{nbwAkPP-3# zS8aLofBjp*Et3DUrYop0+H1enapkMJ&-LW#q~n(U=PpdH=bU@%THfB9UAqlJG_F}Z zST}oWQpMDnO|2^g9m005bo(7}@S*s|IxX{mJ6)#DROnL9<&-+Q_3xwGzu(1OkGHg# zxv}dz_m3un+kGegZ4nQ$Zk|71EsiVlq4;BoxzgeC?|mL>G$&8HUC8|T|JBU-hU?ij zxINs%sSsAMc*0!418&^`@y~7L*)Ob;f7he+I613${*sD46WcGd?|Y@M=fCr2YESX% zN3WBf^}P?6X~VTrIpoC4Pp>(v`DaZ1s&}#VxKJ!*@uHCXZ-ufRGYOg9eH}g{L^hXFUat_TW-UR^6a?e*n@;=)^=vH0^< zOFm){lk*5W=>B)d)TqnpLTP!+%0mxi-Q2aAu|4rcf1j%3L*Y40419N=-PJE#)xG45 zPM_I{qo$?Hq?>ksw<%|0eRE{mzH=9%Hw&*8`MW;dOJmx$i9e>;we8nDzWbyad+DPq zY+3K?)3lbrh4{oSP)Qj7?_NETkkHwQ_tMukXMVNNJ|FTJ7 zD&MtpOs=IK%h&x4f^XiK4=m`A(>U`j^5QBS~i-`3s?yyaTj6W}b zioPE*@4%f;KUb8vMz2{T{*lAp;n#+Z&6>*I@WZmaok ze0#K9N=WtUq3#n=Pn8d>yxZ)5>Q-~L1N z$@1mkVcQ#^W6qHpV9`=}7Ok-ekuu<-g~N`O2?Pl%KYx zNUgq5VB^ED^X2n)<990}m${Ic66xwm}(wUZPFW+Y`H+R+zyuRov_mlrq?3h@? z9UOMrCa4vD+YvLZhxbT{X@I=_jA?IIDT_xrJNIAQd?w;j^Y^~jYb2gB9Ps4!X1mn2YSu*7$tJsvrvu2`t z4O4g@K3uh`u}(14boD}k6M<}tUBpk#d>(b(?dAEj`ZTwmUuJK^QA!X#biHow=^*?eBEca$B4 z7HWi~r1d|UbYXCY)Rcc$_#7I=#`dW|m&GwgnCi^6Q3O!XMyFsSQfZw0#OjwfP)$jxSvz+%bT?+pmbEhP4&NYMC zCzsDETAnvEBxuPL-P?u&FZS){UFvXm;YX9;i|Zqo-`*(~r2l-o`^&P8 zZBEXu%yq__GxwfIFgm;PjA-Kq2KIj~5&ZHmlkSM;J$Jn9-L${b^1jzU|B0&)%vDp^ z|03qcuE1^AnhNUE&fK~Ci+O`*;@#7WFQ0GwnW^_I>0WoxyPNXr*^`|Y-TZy8=EbM| zT2+?kuaupdSAVcC-th{bRrdZbcW>k_T(~yS8|KvOt=hNbz!i--=YLO^ zGM^Uomr>%MH+zKJx)d=>j=9^yHmx+-HQ}0jQzdKhwhijFT}-C38=rW|eTr_=`7b6s z)qnrb?mcFk0&>mBVNJlHlj)pOkCh%e9rsD|W=YosjT=AXCqMpg`EULr1;xyR zJ7?Z_@^ov6_)T_%AX&>jqu^#K6F$XRSUhAoJ;>e$#~MQB@JM%a@AUMc#GxcV40U zaAM!m$3~G^#&@MmZymUCyR@y;OxaHG#md)3^Dgb2VILoINpwMdX1I0_)82%m7oDd~ zj!=kDWwFeCdCEF8^Y+4OqceBsI+nB4=@zK&HsQJPCn8tj zVRzfT=Ho$o&qUOuNi0fJeyGp;d0~tEEzR2#?mNU47JQx@5cxkaV%PePPl~%%r^R2h zzwHq=U+USD7rr*HnA(gj_jIIxF8?f?AhTJ0!S!R)+y&<;zK>V(osz0na(T|$-%qYt zX_{Jm$%)e6!@cSDCYDcLQU?S*_nE(Z>X&<;OG+wphs%y>$G&@}aXz25Ij*}lMAGu4 zgjkJDdcr2Tu(j3yTUMKHI=lLWY_?F@-p3VNSKXY_vt<4j-n-Y^vzd>n)rL%2R$Rs$ z@j69xzx>_FA7`IjboKdlPDRVa=W^vjf3+WSem(tDXp^zPE1wd*j5q4<=S~btJjIr^ z>Qa*ZAM43#yIYPVrSLBZG>Xb#E2!DFf^ECP7I)@DFSZM1O|pslmp0F(J1n7tc|+dB zIX1#kbxXD8+U>b~(beSR*YlhAt_Th=wwf{PfJ|@N6$jP39<@7VgoE!!9C)x^#=%aT-N~R=GXU`s+1!s=jeSXPwx?;|afIZW- z_FvW3dbZQW$Mnlijx8#?_uojkzr=6pqSucEA6!%VHPa#5GW1QO^=bA6ZPnbjFN&Y< z-(cR&dTyIu{C`>Y_e~d<7p9bTzTWoco?xAc(5-gXRi)R?mA0L^uA#ZH()RM3>+TO9 zGMMhoJl->-=x6*ijw|n5ud43ZzO^YP#aSW3;nT{OsxRDTBv+jI%DMGr_1!PLU$0r} zrg`PBx9ePbWSU_0Qy(57xBP^v%^tZwvQFRovpqv;%cQ<@zkf(PoYKQNziUrI=anm8 zr|M7H@X+qC|BdrW)psQ)sY>U(oW_;P-e2V+y7~HvD@%U33tumr7tf=x@637Qp0!ca z;|?_$o;VpCxA?;TJ=tOV6Pq?W3k9#^jdtaY(NrjI`S(!IC|NXqcd*+3Ds@xVZ6&W< znD70pI()0r;_GiQ=hLn%sz0pX`v}a|x+J>sjL+I{!M;5!wbS}kFFtv=<@4;jPE33y zrMcg}mp|k7zUFn->S*`fW$ZrJ=3e|1$$R|N{MErscYYl_&p%;5+leqC?RyJ%R=*M` zujlb$o@RH2_Z0t(wsnk;U8Rn(ie!nVEoJ&Ud&~K=B7a;Ka?G^e;v-q5sI}X~vokBE zw!N?QUHj6*e3@Fs|7T|{H=MKU*v);@7VqlK<=0FzcvPFne)&kjZKLpizP6nWnR{l4 z^G7`KnQ0ik==jC&K1Rna-D}r;E_wB+QS*|@9qwq>Le{*+KPqfm?bU8RdBgN~C6{x= z^3WX`namo`(oDYeRwn({kCn;Vb!|&?uDt6{>C*)V++&0mzT`bFR&a1aag6&Gvx=T@ z@rg+_m3t!>9^@;jHk=%pmS~(|^Ys3+rp*n9{#{rr>~mbP>eRs)kF%nA%Peok9BOj(9x_)ua&L52Pc^q~(@oaMc^DJE8#uIa$ z*z2?7=fn$iDcTEiRNQqs`mU3^_t}Q8GLO)TQaZJE zg4wL>^5ErBsii3&w%2DyVdtl7pwD+F!SW63X&IJ%GA^-iZi-w4V@qE*z*0->ir9ISetuJFU+aTEsOLQ zyd5j5wNlUcw$fU=8ySAFr^HS^h$*>ie6B%c-+GQ4H-q@S>dWL^)sNo1niRSG>g^Mu zKQ{i~l~$dnvfBCe?e{T!%Pglv#b_-5zjn(f&D$%UYlpUc_KaM}dfs{$*IhS;?#S$< zKU^~t#qXb3HzW1EgZ{Z6)8tsZcY77xD*aj>&BLwwY)0>1#+yF>?hD#)zZWPUac|Pj zqrnE^Rb6LPb1rNt?7zAsRNmi--_SY#Lgd5Bx$2yKZ|^+|-gD!-kEqRCyNQ|k@hP=a zXX@|f;8LryyR^IHn3v6o40qwrtN$-fpLsHTp{rE*`5u7^sa@MOb{uxN^M8Kix&t!` z^cHu1OA>$b>HgxJhn_2IFQ3TQe0-!S$CoF+{bToQ-6>uHTRY>xqWpnC`y{D9I z|GwCk72~;gaUJu6YPp#0dAFW7O_0$`YSLYM&~JkAh6hI3cR#GIOsp;3t5Rt2va!ih zRyxTn^tO=dgy!j4KQ^+x)3aULQP^hu$T;6ojoo~=_97Oa_2CTW&0lvmcrv^{8>hJZ zk-_$i=J(4_JQDA(xhL{c>P2_;_OhKjs{CXGFD4jr^=S9L4&9kP`B&E7xihU!@U1#^ z;a0vZS-e;NJ# zdvwt9^!G-ew`T5Cdu7PUwDQa!txMM3m!6eQY1ExE#j)zaw)ac={Tuqt?q13MYjj3< z^`E?}C(m|YUH#Xd|4e)dm)*wiiF+)<4rd#jebq7D?QiA(H-8zOOlHL0`T8rSs=R!Q z*GHY(r@|k^PMiOvzf^k9x7zxf)uyLa3&p;#+VNVr-F?*rt7VD$Y9ABtHZ)HSd7f~+ z!g#CJg=G?{E99LvN_p*(HoM!$`0S^fv8#4hY5%P!eV0D*~l*$ zHkEq+{@)LMwfMby=f;nXT3V0$#crN3iSXaKqV(8Q&W%2OfxX!;Rz2Q5HD*QC%@2RS z&gEul`Mi5gVOnL-+FK#DdW{Da`*Yb%MLU>hC$Do#zwIi1L;WrL$?K||CtoN@hZq@) zMC?qvdH;cc<))>LVTLYBxi#t?g?sM&Js9+Tzi*2u>r0u!EAQq{IGWiJcpz}q4=eT= z-_*XH_*GF?a)Vn^)RWC=|be+!=3F)Q8*dJrA8$1==(%>&iQnKn!z$3@rO->Y7|!P8DZ?#Hu*ll$iR ziM%m*@c2b&QfFP}CWVvR=2@({lXZ+)Z27jf!q+#P8=RsK?a)@drmWzd;yS~2Zo0># zh105Aucq{!bh&@(`7QhUUW0SW*FCJ1KFl|l7o7gS@4R+7%htuY3$8@ipA31&FIEw> zE8yXY_Ja*aH#Vqi?`1k>=xOkGv(KUv=XOW`HdH%zm63N3*S?*t*LG;6T|34%PiPyP zMdq{gKaW$lGp?EGd%Mqh#r3}5ccR}if3D=u67}!CEqx}7ZMWXXoi#FcdshWA?Ne3} zyDPhgC%$*l=Q=%B;p_L9mmbuRyb~TFuPkA8WPe@hy4h1#*u4+_tmCq4!w<3NXPs=S zR)tII^~&ttml$BK!^tyY8~-k&4Gg#RjOPf41%F+r^?7l!q-B})WS8GpE^IxfJbjjH zqq}O$Py4VW-Zi_iDJl5ap0grb#8=H(;a}bEyXWpo=Tj9?fjm#O@72H5o7!vR z$aeARx-|?Y*$y`aTKi2JM;^2$|7I=R>9Tn5v02+$WpllaHfD78 zc((nlW_ZOEduHX-w1c0%z3on)yo_CPv&QUs%d{MOU;fvc@L`8SNxOVA+a`%W3;wlo z9JniA`mOqY#jEWaha+6%g`;y8t^b;woacJ$s@s(LCw}t(`X^k;f2l0_c`Tn&@&yUu z-iFG;gFlZZsTZ`q`)@k=dP2zGAl?rpoY~vt<$T^w+E?3r8UJE#1r`5P7{ z_w4uUhga4~uRP5a=elkld&r9&N z{<_a-*|J4IJUk&xZ2wIv-rvsrtgV?Czq|^3;KVZ z<(}QEOEwu6(+#EvzgxX3Sp0z1D?inrQ`Vi-&zAgTGt*N1?$@nWP1?SGevGT9&97VCjW?9OrKucAA~so>9nuV%?Glo=3TY-_4iP;JfVi zKIw~jRGkN#>77T{&YE{`p1$+gThI0J1|fDODc>Hj{i!nGVVZQ|qm19AXORdn6blHR1x)7PC{ z6yrJloAlgy@?O&7H{Q*)xtj7v-$FpNtz>OV@4jk_T^j=u7OlEr|NOzvi;5yABcFP7 zUw+uQB&<1A<_*g}?b(6GhNfLzQy$-CDT@5~`*gkH)LmTnji2rfF1>%{ptftttOuVK zmx$LaP+Z)_+cDF*S8cC5N8}TIC$|d^JN&L?On9a4H#J~gdCsCT0qeKHh40c_m)AMj zwXrO<+JBm(YyF|TXI*htE5A%~*A|%RyY6n*2l30+x1Y~DBKnyn@CAO?g$UM(EZU9#`w>Q&#fWcjiL zI9>|Q6uQD8uJOxj!j3s7g`Vl(+mR-*{C5P;3!ctXO!>wOOAIwa?#O(a_`^I_^UcL>wf|7>1zQb? z!`1#wk7xdL5Z%!2r)bZ8#PP}YgUc#cyE)5E`Pc9~EJa50irhDozc*O!&Qm$N*z`h& zozvgxcbPYzzghP0r=j+{EmyYOkF%LGIpGBJvB3D+Cj~OSxldY;s2fG^RK6v&Zsob# z&a(xJs%ECWQxI=BsqN(BoydFpE#K=|@rVB{l@|z`uYP)Q7?;%Dj19NWA3C~#)&-+3G<6k~6Cnv~4G%AiqX0#~=9!~cig zJFdQ9sa^KMOG4Cr_v$$nYb~PkH}!?**<4Wbu;^opc)2%Z`M>rxYwaWgZoiwZJ1uVg z4U0z?ypZkGrT*eAs{?x5GPH`Oo3Dv3 zn(&n@a*qSt~(tL zZ{B4}%(0s|!9QeK`Lo`&x>ueY$V+5pVNGuEK7C&z?((B#vHwaRB>8#lX4`L_sHt2# zmEShwePa}N&Xh2*J*V0CKR&EedenB7{w2$TI)G_uWBx_+&e)8y7QeW(;fD4-{%xeC2}4S6uGDnAi1#F?rI7brKBcV{USNV2Ru_J$TLTXuFBaQhzL%&t8?y z8K=N0P+V(ne}b=Ux)#&CMO!w`k@J&RO`mu)=K{ySPYwZA_nIGAwD#UQ?S8_9OYM@} z>iGtOAEz0Fhsn!ldc8dVdD+>umJvp=SJ&#>2u(2Z-)invd#k=M`r@v&3=ZpNzD{46 zDJ9x+{q<3wQwwAdtW)s2H|5iY&&M9>?bMliDE;1#J#*GY&6^;1Wjbd?-b-Kk_yfX) zb5FRZonX#>^utiTrS`ZR_XWQVhK|i@YFExCCyP&4x);wo z^dz@!uc?9I)^(f1%&va5t&zLg^D*FW#HA&Ycgo!R??tC7vmfT(#%H|zQFyM)zkC-C z^_E8AyBU5TCcP*L{CaGk+LDI0DaJMN^;=!sSKF9%Y&p2=+$8OQH7#$1Yd@JBnYo&U zMcY6xmEBfaX@bAaU*2sw8O-{cPenH63dp`P(VwV#cg1zLu3IXLrbRfq=tfksKL5K- zW{>7Gmv35?a~M>xW%ysYxc%#y3i$mq!aNOqITJ*0{(P`> zYv%j7s#kC2InE0Fc)aZT|74@0rD3y!=Ej_9wvVJ*)yIy)NvoGs^+YiR(`~S}RB^&ZC^2j`Xncsc0ea-nJErQGq#-bG;{uMa$_GR^o zXEv3`dac{BxBo(8@GZA(-zG0O<6{yK?J!?%bA056j}~uEzkB@aK^94qw&0(~UH)#XTITAPisGMU zvAp*bn#8D(Uw^52@1|c%KhJ;t(NV>=v^UB!(Kz(I_wD7kAHR_`U-)j?RJYyV-(Rfx z$ZdCsH}yVGtjZ->j}4nENeQ;0m|7kZ-Y{G|kMmyJn*;`uIhy)zBJ-2QhoKlD{@ zBtwQp;fIa)Io6mZUGe*=zLV!bP|NgFQHPhYcU`gGawOq`8oPt>{Zoe~1~c!AUf+J= zwO*`8!#7Sg#RY6z4Q{ONpSksLi0TQ6%Yj!pT)+O2-Y|3j;^cJM$n9dIz3w`aQ)8sxlKf0X?d|Mt~YX5xp~Uh&N7 zpI&_?OOa36vy63u_uKS0Dmk@ViuYeKt(JTvpK-Bw%DWjW4i{UyPZbK5_Fl((lUt=@ zV&w$q>cE@`)rIG~r0a~nW!awmwa9ALUyJ!a89JI-m)l)h=g_kv?uuorqEY7jzFF

dK_mN@yC0rr(@_pkD&mEs54_GBkcF)b;?w<4gO0%bp?_tl6KYBY}K7Flz zL)FQ%n&!&7E}9#7B%~U?E=YU(;D1^-`@*$Ss~_F}8*kFXStsiA>~#JLp-i{*^a)ln z;!!IaN>sko&wRNm?DqcaS~GVpdiY_1$fP@7GIcYHu1-mQw!{2)hd@t!8JFh5kN@?j zUs$YbbY$`U>>b?4i>@AAmXM<5H0MLsnTf8Crk9JFVhsm>H_av6<;w zgrKR?rN2+-si-ab+&9mn?y#=T^(1q{u<(4>T_JTXj!Y}KZb@btR*U~itli=G#Wka5 z>d%FLE-y2faHehg;iiwfx86vfd$zx}uxzQqMEg3=$Hz<7>}+ZlCal z+}u3B%b4b<9Ni%AT=qyl^=O5I-o{EjmDkym^@A3qmetGJ%|63@pN+A&f5IhcllCmb z*=Cb$WtALj?-WkTKuOMJ9P`Na*XN>!P`H*FX2}V5oCFA7C--WUrs> zu0WHQ?QbrxJSfZ&GKpj1>%2YkJR1_P1~qb5rX_yzeKD)o`GNV5cMC!TkF|wwFWpgc z!HS3J0Z;b{(^_vPJO8&weH}E@V&;C0cM>h>$<^WZv)Et%CAK$%WrE=lRE^mozN9w*Fd*fWwo+57`ey z=tldSbO^YeW=u4)v1Ob-cg|aBb~&{-rx$NKye;|lWKZigl4~2!xC9=!b~Se0)_*U0 zc1)J|;4o*G^e(@-_PR!WrcLkO&wl+%T5ge_%2cyYH*EV??fv4uefpFRPxZBLou(wn zcZ;h$cAdoe|L^bHuIodWxPK1UlfFK;xq8o^*0%3{9EML6eevpSb5y=U5Qd5MN}R@vr5>Fid^r?G8|Sa@pDlOqMn zZ_Wnxu^w94w^jQ==z0sLEweVAp3y(=?dkQUDoX3O=ch3GmE1ck`AN^8Nk%EZS8eBx z(;N|nc{j9JSq?4uQt@(&UVUbhthL_}9^b!5OE3Nna1Q>UaewjW)29_4e9cR*-)>cS zd8Uhf%U{2(*BrKF8gv%#Uvm209TuBwfvkK6%ieIP9b3*)C8=hzbIbhS)<+hcXzKJ> z>Jq!idqTv+p7j$BUe2jr_+bCKlgg7#lGPUP?%2e$QoVB1-c{`1ec_llhqay$c!+IbV80pG-E}+3P>e`ItuU zdTrKwmpg8BwrDQpR{8TJv+Ha8nrmTM>$ZNmf7&5?-|=|I%;QmO-mKMmn%FB_c*FBZ z?@}X|h>I;Zr!m<5{P*V1$=BgLr}jR$ESW2I)r(<@Vh9&oliy+M?!OZ%=dZsyX{*Mi z?K4)HX)fs0V^o^C?uW+V9n9e+{~Ed)fB*iVH7AmP*GbO@>zq1Smp;pUe&6v{=Cw$- z7fhxtceyVbbx&HG_Ws2b7kU3l$BOT7pSU@9<7IQ9WEPp$@ZX&L7Y}f>#ZUF9-6p!c z`|!q9)^*E64IdpU{cH4h;$?5$3zg9oCTB{&CLR!+U=rS}vD~&jf`-ofo_+5)wzZgFTU^6l1H`N?a^d5x*X`B^z1 zz9-f-hG<`@shM-XYN8%*if(w$%TJ6ND_m9kp>#b<@ulv<=`;7;-#sZV zUhm~j8M(K`4l3zCD^HSK)A$>jc;hmXB9?!S_CACFrS*L)Y?~{(A{@TsK zm%qB^@2O-xsnqKG>c^x0r)%zJuKRNS#|%l29lbl={odS}9BWmV9#dy4pJ1eV(De@fVY$ zWxF}zg&rR$n}7a_wZPVR&S@7+Z?p97xOC-jS)i{!AJbjgUwS;pWsfwJzn;Ct)ZA_& z+wV`RY||tc|4+Ob!?f%uSEK744&Ivkx29_cK)%Ebr^$B?ouAR2!OM9&l~iuV$sjp z#y=OTEIf7Es3@DOaqG3#?Q{J;{bBa9$(tFsdZpZz*=MUdQdjZ5;m%2C&0%#&mRaX- zBJUr=9d2dO>|>$%GRTX4wn@&(FN;gd*1Lwi%>Tv2wrPd`tTaiJwk2u)&YH6)T3Fm- zdC_yG^0cM?L-VFfs#*^hFj!ridN5npt9IJuj%oiKZ#AcX5_;ctv#IOt>5`_@si&KN z+_|)XH~h{gc1A0y#^Vbv_ia#d<@%x&RWo^4KI0mjvqp!KX2ptYdv}LyEc|F{cRd>JS9Q$## zB+28i*)*}9VwOdn3@(?Jcq?VetjLi{cl1=7*;D${Kw)um%b!-y!whE)J@Tr*q})E% zWc)Z}^~}-*(Mz7oHmXlglMe2z*xu{0aybRTISuiD7V&$yd(Qk`Z@>BcVxK#j#%njup1ZUDsP+j@ zg~E{D+p1c>Z{OW`zA!^$CiA&fOEN3M)jo7Ay~M{9>XW!HX6FoTZG+5+gRGJZCr;$N`*G)G!u36`6Ze+d?bywFOlZ;E z?-Mh`95?-AG*oWmR?v!mSKukev%P&{iqX?0?VlqK+kWoyUw<{~l>Et~W>bEq7bi)#o!!)o0Z>Svj{$N9L4|Q*r71@O?j{O)rG_f1SpfxBk%E z6`Z#uZ!t{n6uG&q;n_~V>M#|qYeuDNRq=ea(b7WK#nU1@o?WRsSTo_gXJKd1-08D& zxz7=&gLRv1!#`zqKEJJ=^%F_{Qz#Gn@qM_@G7zA={4_tOYD2g-xXzVlb7dbH}=ieU{jZg$n2bxn)g#%(#&V$E9)aNNA}sxEUGzUbdtkG znlHme=1=RvS6F?r3f--Ge; z+ZRP=0`~`oPfFhUbAfrJa4P@%?U5&B8|R*WwcbbI&UTk+J`d&Y=Um9U({v`PZl%Jx zh?lcG7p4l`IQiJBR`G35a7KJ?sf^&coh#yY-4K`|*&`%Y`N?K)U(ei$8XM+RO^sg= zysG1MlbE2&H14+218X_=`|HF^edsXf#?~J_L5be7Exy0?;%2<4zaqM3ed>j|%LMm$ z-n`*wT3KzAQm%YMid(}tNS33efh(qB@}5~+<|Ncjowo10TC(S}K1=mpkGUF7NGr_H{>e%UgHR^+KXL^IcY2-C5A~xV}eY zt(Q;i)c-9U(&EXhviSpx#kN0K{&_pco1FHzB%#0V!9EO2H-7X@Uw(YUO6H%wUln%5 zhqGv0&dS>&y5sKJDHlbII`z66)+NO3-?%~d-XggzUI{N`TT0e`*q0S-InA)V=3vHF z`-$}p_w&y0kuSCTqIPE9p6e%G8s@Cob4b_Yruv85_0Crri?g~|)n1E9N*&4dE}zj| zd9`&(*DT(JhnhUh98Q`qZ_pN+IVU0Ic1(EI?yt+r^|gdMfBW5Xx!AvZ)`98CJrP@2 zf0bMOf6l4kC9Jc2r>6CHo~?IsS=8F{dp*t>es~}H+I{NVhBehsqP3>(nE%JH?EJxc zh3b#{4p!USpE`WzmtKv1Ty^=GtNHUT=)Trqv7S0r*!!*5r-e$9ZeHE3y#74PL|*xH z>h|1}ieK)lIP>HKIn&Af)4ug--=1Z9)ux~VW zplJ+?leXn_zFPGn$I?8Ucc;lq^O;v|_OE?(m9=t>-no6xIYgeE3HZY}^+oxCl>v8` z2F~5Dy6C=O;3dPEn-woxR<+&#G-LAelTj-T9#pkgf981deXe@f(`BXQXEt(hb$+d6 z74uIQvS~WqYj}=p&5r(u%V#J&&WyVlyd+?MecQK={w))JH82IS|DAl$;E=e7kGnul z1@DA7X@-7b<=w#_ZSO@~yYTD(=KJq#JYPO~)&4Wj-y^wdmi!*U3D#w6&L7#wGuc|z zV!^)9Pv3X1`INCi;HIp*Q_=p6^N+aKF4_`1@5b7N$3L?0>hGv6%endYOLqwNK#x_j}FD?rMCV>+Qnw?ocpW@oLkJC;rHJe4b$2cJTT^ zCa2?82QO-!nS5}f-s6HRX}0(E7ud_}|0pbT;|3RVuGdY`Znl5*krDTM=ImQqXq#>_ z>D7n5?9m&H_jOs$2{SA23f^ivrL<7Y*ucrZwyU*Ibl2}cSu^wawl)?0VAP)>Jk4Tp z*AtBdi+#oSPnUj^`t^39)93Iiwl#{!3Vy%dGnu>5f6<$eT{Yng|1~a~6|*npujQVG zAN7@MKY!u=;hA=z+3!%fM8y~RyMID{2AF*B`rxZF{q+q*%w@|b$yWFT|Y|7h6HnJ#`RM@8*+ z{@m8btZZ2&9{A2<)^3L!zrdTOYZZc?KRtVX(Zpq9ucv;moO7>Fr|pvd#v1QuGW*rU zQyt#0xSX2um*w${4VGPgi96S1YFmnx?=#^r|8d_ozu4ul#32V|m5(8Nj-I@nB&-%| zJ?FZt)PWTz=kYKt*~>2zdY98_|9@4@#jJ*2I;M+jkMI@dye{XMbZ(JM&To$AGZ-U# zgm~x6p9*O_8S+5EcEjzNiS|Z21T5LF%b5E9(o6ua8biRA@K^;-^Iyb}EWI`gBl z3l_$&?h9JzdUCN(%L#tv#&UXLukpd&nM|=dZ(0~PqaYMZRgJh!KVa%S+R7L8ySn5%&xw9YWu&FTlCr1 zHzdCE%g_!?y?-*({?N%`1^X4{kkW6Hasxh?U>lyWa7Bz zaLXI4BhO7qUFTN6H&+6GQPC~E1WQ#3i?Z+PRLj=JqLXcS7coSpG%kMq;MWP=iMO28Oo}JAIhboFOwIqd`B#_eG~Q=6&wowT zasO#Eg{w*VyJObX)Ual&MIV>jzB;_;?mnT=Ne%g$67jQTdFP}YOOCOSy6@>Y(e9J= zxs8?1C3eowrbu)6PtqwA-oEDa-+nK4mIGm|JjUFLxd&3N=1lRqem}mxd6sGZL4h1o z&$W(50(YmJp8T2Lw_>^0@&kV#Z8sAxKhJetSm^B3q-n3d7H*UN`Nn}M`@xKgyPW%9 za&f)5W$RiezaZxU)06kdU*6%+l#h|^iks@6F;n1N(z@KAjy~+GDQrJj)s1C;2n(SW)wI zjbr8XEj285KfIo2d)Ktc?$^8T#hpOiXhs|ibt)&y6{|C%nH zzLJfMhZiu+b~wWMm;c6sgyY-Tr7!88xBh?YQSqhVeYgCUnf;pIlToj%uR)EDmT?3nX_L!R4={gd62 z+e_B&EpbnctNHS4>a+UC%bKnB1Wnz(`bEZ+b*GQbxBe-;U~j3kl;@5&d|eA{ZXKG= z7JDZu^Q9rL>$fC@*OkH_a+joRf6o8>v(Ij;txVWiU=Y5rIB z<$6ljWWO354qqGS8D#5W-c)1Xv@Jy;YSOM%^*kR=dd@k&GD2f7A>mk+spMWuC!2!#StlR~+8*uLm{wrJq-nxGrZF|? z2_+sfc^-d7_STsi`x|?%WYg?33E6{v-5t?`+|W|7Awo*aa&D^Y^aS+aUSG z@Xh}l?x!DQSC_AAQ@#_!{jlW6MRQdbW6L>GlDqtO{92&uA+*o<*QLo`o7Q?e8sE|G z^cRb({Cz>?XqMs<=G^6*?Cp+!e$1)rq~QE$!ZqeKMqZ~672mm&xJc)4;X|gB=Nl_T z;{W#xJo~u!%rpIPjyINC0Y*Q{mgUr6a!}RkQ>&5sS95b+Y|2wEGx-+tr?o|_o3z<_ zyk)gDF220u^SNS9_KUMx^Ow)HDaqceD>Uo#*{7UU6DlGK-Ij4NG@jdVQ6&AP^5I7c ztQF^3Ut5GH1fP6nXFu=dvN>*NlMl~X{50~=4wv_FWvefqiFlTH&;C((q>V_e)Q=t$ z|0%W4IS%=;TuNwC@A{^&^2RZ?_y4XH?vAVf(U>>oZ-~o=Yc;n6UKBMv)p_xX<8f)2 z>4Lu37O$rN%j|mhz(0P|x6mf-#%w`$&NdgfGYS743$I*^I?uqeXM?Kf+jhS9KI+GH zY|CQirCM~(+1C@|P+T6iN2Gu?I{m}DOV3X3(!LqtZZ2eQEhG5gw(l?Tg9|ry%3j&; zn>Q==dzAam9<>`{lIO(d+^*j==TgPyxQyP9iLqx@SdO)Gy)7=PGEQK*(Y4~xH2ci0 ztnYKPjvH-!*t+YX(&GKM&hGDGy8my}&y3$QrmQWR{`P#pr2Zb!Gi(Z{{${gChVIn3 zek0maX?9+&vtE*Mk;}}e3;Q-OJD*#$!FcaU73Who`Ak;ZoMo6}@mSTK?J!&Yj>!S) zI;%P7%`;)WzP|1$mwJ0#Du=nojeT*GQsqUQB>Uu+o-O%Vtn;H_is%#PhRIi44J*nd ze9gl4>h!C5+o;_*CiUWyilU^N?pd3P#V?sAENk1HnkFk#b9|a@k4qH;^Zcn%x1Shi zc+LytuKdA%aQE~ZJySC>cR#*aw`aYL-^@Rr^Zyi<&aSX4)&0@WFCs6u z$2I4C^G#QrFYbLK;F_f%DXJkgdzbyQ9T{`JdcRl^&HXj{aMrvwpBZnMeS|YxCwWhm zv=z_T6m7CT=tZ>(qW+awXPBh_b-w*CbB86k^& zRhMUNS9`Ez#gscWj?-?vTzy!(DlqCB+m)>gADzlst;c>zA>iZp!X3Qcf-Yj^Oi>5C zKdlT8UQnuZ(n_)G{)u;Xj~=R**_^$0@PN+Kjb9F~NH?{vi4Ij>XnU$*PK2YY>4Ph$ zmmLjrQj}YJb>)86Cjx8NEUlZ7++eGJJJ)Ku*_t|4*DqIs*xm&myJq?OPo(nqtXEH$ z*?Ub)&(|?w>^u9wzymHpDP|Y`GqH%2+TJ6{+&NkO=`Z~%^Hs7vlP25 z`Ho-K;j%cW^KF*ea_&Fxl3DH+u2-GblYDAfboss+3}>sNt&fSdcUP{xmiKDQx=XW# zk9do0k=)?8``E6xjY4u7zcw2PocWk-vByL|{Na;D?61~^PdxVeadiF0%Ja_!R*CF# z_sPojs-B>)`nalVO{_+|+VrRdEx|KWHTvXU96TY>TbVU4B1t-Wx8U?}V~@6&$8XgS ze&m_6v;A7ZoQ5w?^-Br__FQWcHkp%SI-yLYV5Vio*BKwpe3Dn@{yp}s$W(BdZ{y~x zA0I4awsu~vHS0**qJVq%*fJCsni^F6_E;Xd=H33ahZg1hz1d#pEM&wP{N16Komt3$ zXK&M)Uk#lV%Sw+tzG^mKF6@2#LP1ugSFamO+YQ&mf4G{3jAam5T z8jI%70on2AMXWD1T-VUtyUC#XsmX2iE|Gr5J2y;<_I8^a{MB6Xa)3q`*;?^ghGkk1|ogkmEd3nXA2A?j=*)AVh&Q!gw z&Ac6VSHeU8BfpoN`~0piiT4~ECLQ2g@IJhLvvQB(!!FOrKWx07dY|R*>}xfP`!QSW z?F%24bKC!O31~4LtaEHFKQR!@{_pc_cSLKqLwd2%P?J1fq`OMN13l*j_{k&VS?5=A}j`ByH z1ts0_|5aN&Pw7s%bvMahxOH=ExALT>3w0BR=CdNw}|DO~f z+)-3}TmAKo?d>hA-=9rkt*e~6+a|U^!RFz|lzIUS>uvp@L9ddun4xHioH7^WI7usWc7(xPg|wY^t#H!zhY z1GqVK zv}-y`i(fy!-&7{$y5M<#eDLXyrAwDM=8N3=<+$lq={GB$H~d@BnzB9u~c$>-6bLXy=`tq&}EzpqSoOAZ&s$D<7bYJjqjCx>ndgd&VrLzN+ zeYvkzcYbmCwf3a>r9;#B3zsBpeM}uFzjb%Ng$r++bb7Vk*KDZ@Tr3 z{jJD1T$f6(JZs!?Pf_4djkV>Z38~XRFv=Yc)PG>7d3A44rC9f$1vh$~Hk@ZO{7fugtu9TrSP!BeONPb5`H|MA?tJYmyU;oppSb*=CD3 z%*d9w9JXAynsq0)uFbow;}Z9_>pt1=DB{Q!?(pN`o&O^Eoi;za^k&Hhkty31u50*n zs!4MwJ~(*m{Y_pp!@2`lz#ObVX#Ej26 z^1h7NuM^@&i%)(rJ-7MTe9!->);A)S`W#u3a!2N8@YD_0pH7}?lksrZt*SuVv+Qr8 zvRP$<^{%BU^`AcUdc&0!JQ+p}`(iHeEq;_RdGm(fD?gR0dWDx;b{Iq*wt3 zmq+P2KRCKT`|c5jyW-O-Kg==s6ZC?+V`^n!M>SYsL4NBY6!^?!S3a|FqYgdG%YtJuibiZv82{HPczpaSzXW z-!-B>P0o;OO)rOO-XuAfhk46iHr4jLzFA~1%l*jb%$lay>g7B4%`RxWbLAml z#g%r!O7|;Y6elzU$|v(yudkT(HNu2F;l-yN3*}9D<5Ywf&DfPEzG(3p0Zv{4Yo6{5U8$|r z_Nx}}7C8`C{e0Q!+BuAmE^cl2<9HWwH}+4#{)p09Gq}HAk9>Jh__l!jS=WHey6tmz z&-$=`!~P?iJ5Rh?qjO&^y-8sr*D06e4GdftWhO6tzH-kOzdMKD7R>+7Cg>0yZ8rZ$ z&Ymr1r!P1woO612to44xpY^uNY8T$Sl$90y_PAr4D!k_FHZAqtcW3=)oA|Dx#Gz{M zpS{oQC$6lNcGF|++VWtj?)q6%j5OsoU5i|PL7s!_oQTSFj(5(6tky5MZyLWk{Pd{k zOBcD0vXtLD=L#*kqIAutEbRCK=ZD|t%*psQY5A{h4v&s=PY(}TKSw^I_>e>T7awb< z#O-0Ts!Wc**shn^p^~o>@v6aZqL5tt)jNf6vrk?7YkGF!PA8R1i#slBG5wdyD#}}L zFkyzlY;BImQ36aEd%6xhI2KwReIf!FMs9xGHP8Q^N--vH%#x3?M(|3Q7U~@^xgBR?*xk*_S?mo^k!DE&ImofI`7kj z??*0Wt4-JXD)dVz=7^r>8wS~rQ_t_u|9i6RxwQ6I|EkW(^6bg>XU`{Z?P)V_m+F|e z_mh0nvw*pm~lINl`}M2w7Lx!Yf`Zi_$5C+OV5BlgDV zl$(omrb5Amm(hw-!c|`H=b5i2{h$B}Oer(OsRM^R+f48Zu;N{1R*-JJsD5j`% zv+vwoaB#8W28$OOr*!LC4Oz~02mksp>kQ|Ay@@wWZwba*v)NWA#Q5Dwm~*dHEYDpo zcexy+r~djwGv_`&8(X}0OOr>)+Tvut`5)XLxxG3mRkLtYi~QCtJ48-8o@VvD^VwPE zh4%$+ll$^E4oWqDnOIotCbYl%q+0F!TFz&`w^-?vZI!YwIuGVBc((Q@ecD*2e`n*{ zeZTJ{Z&izw4*Yu0{zuw@+e;p=YSFRYob$x;R-f+V1#yQ@@6%YUb0|KE$*1)2Gq3d* zPMkLKl8;)N6_VMuJ5Pq`Pn^lY?(OXL9eZwGS@`bHv12=WFM0CsdKPavN#Xcq=cL^s z6+S#}cfQ_~$`5}m(#_*$`7iPC+jE>9v5{-CyPqwwSQKS$tlP}vB`f}U$JG1zd$|0= z-R)QWZQ}be&x@aJ&eG-bxATRX)!mQ&nf%eo!=&L&`O?;?jfWmRE!MR>IlvuKUF|ytu46UD57lv?^<)x@*cm zMnjj+mrj&SoWD)_tB;d=)#Y6i^Jni;tCSepS#-Zk_*k zh2YY;xziV_-Tl&Jv(z{3r@ryAJ*~Wd3bgptFCR>K_4)2x`<`DhPd9WqUOs#xJNSEr zjn3Z?m;U|`{=+HxLQAGbL~9vXbxYh>|K!n%jVqgFbhk-xo4hoNY2(Ue-&i^oK`i>K>=B!zy`}N7HU4~cKj&Aw! z(Vcz8wtz(O5Kq1))^~TAXPK|zc)rW$wbM_@$*aOrrW{qwec9|J|GYIzDdqc-1$$x^ zcm``%!Tgsu-c3(*<1(KR6wUBYQSqXA-LiOR$@zBQ z3}tVs9e${=@r_5caO{ImFJDNrvqm=G59WmTbB zm1Zq|&olY^nH#qYrm#u;Q8U=Fae}6j_b)lQ1-hA4|K57nyXo%WpKQ4Nj{02A)Xl;% zIUGUuWnM4jru!~DHBWE105|_5N3q-8-z+XowEyC`!*7By_k-N0#?~9VeKtL=*9&TJ zQcW@KvpaY9q4;dJ7j-kW=ltkA#rxC0^p5}KX@v*nV;NmTu3ouz<(1K!#quJ7J9~DX zdcB-$&3)b2qo#5F%M5&zrmk7?^!@3$uXws?Pb_ zFV1|DXM2d{((-T5y&Yz{oM`I!oxR`H`fi=fu9a$njr*VM;1hx|59to zcP42%6Pu6SC|s!WoJ&Djd)^!Qt^VcO^Y1wET#goa;JrGf=C(Yvx6}S2I{id|LU} zSCMT|*~^M0Wvc)BYTO*&PF54~HQS#0>E;Zd=$}j8I0f`U5gw zLOZ5hfJn4eMDbKkWlDe!H*hK}UfJKE3BWxObF{M^syyZzq} zqg-jJhh62o3twb6uA05x`R3F;s(M*j&oBG8&AQdfwte4RW+qLOqt(wh$RArHaZBj3 zp^@Tc&dcKkRXn8ZWJ*E5kE{jPP6L05P$n;HIG2Lq2w^%k&#>4vDzqFTb zN$^ge8b{X_PLRbHE{H>sa#NIqNtkC# z^8?p&dxKluAJP_Z-`J_LvqqzM!Rggi>pGrv?3ggQc-!;UT-pYXZ(7ps$Llz~{Bm6U zdbLsG#N&sL^LK9#bbb_N(6VgLiYceAIGr*5qm`^Faw33llFW@6`cKT?DXr$Y`7HZu z(_h<%`f4v-k~$1dK3`_LT}1F9qd@7J#OWJkCif-3Km7ahTg~T;f2YZOd--X3n##L5 zKMsGmT={$JmJga9oTqonGi?%zxii&=g=u1S|NUzU0SeD%G%XHXq{%lYY(admZ<)G! z=qyox&)WfCvK-ar_1Ja>xNQ-do1mj3a&gv=+mXvY#5Yd8yw>N}Uzr-e8z0`Ayv#aM zd27SV2iGF+WPI!Rq+6+SaCde{Y+++8=?3}yTxFe#hQ+x-jW@qDp;H&=> z@8|yep(7c1!shXXcXyXGC#U9!d0lFjsbkI*GUbdf(%JH7s@Z`B#^z-w1CRgwB;=ZM zswa2Feb*qlz#wu*X}!7X zw@qF0sN6f7M|YMlGr2b*c=9{(WAj&A9~EkOcJ)@*q(^UmJ#b(5>$Fq*mY@UdI-VRJ z>wn07*y**vt2n`o+cx*w_6<+_-`ujSJ^ki~vT}=@bvNr#wk?ULWFrmhU6?QJcv>vv zt|GeGO#Sv*r$aF(7fYV&;FvN)U`67bnPGx9`>q`hoxb|z{V(e0o{9db5mnx_^!qQD z`jwJOaI-JQ=6=EtS9r5hq2b?Qv#RM z%Ohr-EseGwu`gt9+ujTnzSC=aaZOg#u?L2JPuP8` zG*emU+$&CId(ztERFTMEoU{7sv^^gzuV)J>P0s&1>DRq&n`M7n3WR#|KeFx!X89&- zGS7cv$8O7$It!N8IXY&J99oFG2$rJ7bR6Ol}vE{UFoQ>W0ePaa%9{4e9O=z|?mFRtzkyX7#QS!n9ky|)d{dY}HL6aVm` zotR;?Z^-fTCoG;hoE!(uCvI(VvfH#%dYV|^LK_p~chf50f0NR zpItRp8ZGmal3ds)u+>bK@5L_l{?&!sKf9bf?^V7%S;^!6X9w?O%L5sl%Va)WKK@)I zT+KYb`OhS_z|>=Z0}mAYR254UTPxzSWIIxXJxN)&XPT*5xG)dMooZc8TvfT4cW9+^#2wnfSNQ`JD7* z-j%zbGMb;eiY4$U6ve;W7p-IZs4r6dX0Gmk1OMy^dXo=*oM_(vZClliG|~Mg95Mc_ zT{3r9-ZT@LCzw3WuNEFwg>M` z?RB|sl*DKqk+qec-QIpaId{(Lz_7dT+>{w)KNdEcZ@bTZnBm)Y!L=q_-qYN7KK&_h z`$EJ57PA%YhAx%g{nsxIZ3t{Rw$X0;X1leF7ys9L%Rf8Q;(2P-eMKgYE9-6;TJc{! zG~qgvsh`6Wo{o9<_SE0=ez|+cjLLTlH-2in$Mm-QmC1=H{g@pRj2djp+e1qh2j5V; z+37j+$BpIELJ!&B_Hj+n5dY94_)sxZEj#vz`@fln1-0fo8!m*FHT_7|ncY6~k;H`0 zr<^8m-CI6s`$F~KE&V^HH6<^!mA75Jq220@;;zH`!mdt@e{O5-EBvVT&SRNhN=Rjd z-NN?TJB#w{^rrGv?eGfxIYWGtTId?i;D^FVvsRlaMpa(i!Ql1w%{O_Q#6tpC9_v0h zSNphle_6Z08F#Hc4F}y>>sOeaKfY5fG3TIAiSq7aA(7!Zyo`Hp1%32gGL`GMr?a~hR;Ptf06Im@y0Fz0L+Z&N;<<@_c0%$9pDeA0^je4wRO^-Vqh`&H?0XMN7uE4lYfY;3ST+sS18? zmpux7|JLq6;auGimK2>mkCJ+{avlZSXy>hdcRcG%@RCMPw2-lsJo5!j-IpxdT`YTTH|*oNd@SGpQ2fNMskvO?+aJoR z2Br4SNImqlRlVv}x&A}TrgTf@XR(hjP_{ z^}S@N&5ZfxYxx()7Z>^OIBsiuDuU<3G2V?Qt<|p1o%{RVC6(-7TX@_Ib=#|_2EFv` z-IBTHx+|yUnl%=Q3m0W>o4&#VeMnk3##r(=U*^$iYcBO~IRDMW zzuQaK&9v;C*A6iUBPNaOyY)o3?XP(@Y0bvGM{mNy7w&LRw||pf@ccr?!c(jbhbsHR zIh>@jH$`7!i{XrEgkpo-@)nC3^=jWj zgFKGN?{j~9#WG%nQNntCq!&41B8T01AyzFebycGB}x{zZR#T*{Js zZ=a02Zg}j(Cl;&bl7x_yo7H~CCpaoREfoyje`hi{@j>clN0{}44c!Yq+wQX!Idf^p z9GNwu3~ffgAAhj(sjt0#@{`ZfTBxZEnb6jIrDhJA0@`NV^tpEC0wxpYSH(~%9&ggOFO zJ6saJ_b}3WE;IKui`FAwioya@zH+LTlpnDdVNQ**e|*98;v}YdD$PH6^27}cuM316 zSsx%iV}A9L$>w^D+g~>2G<^^ZPy5lM{LnHau6e_HAyu{4cV|^s?h8ylcVy-_G2!av zOA4Pmy|b)g*zeWoyr8AWneq9v*&TZqDO=WV%<$j6>8DQxKM%u;PdiWCjNRWL>zg{G zEb!Zf9e)+#7jvIoyRUGK+7(gz`1ye^8k?QEM9SJfY_1dC3&PLPpoeyF&wL(n(u~^MreN^_vTmIfZIX3L! zyStrK1dGglGWxqu-AK42uN&d}@}|w5K$HCzI~69CIIH9|sI6Pq8TaT(So@}Z-cNG* z4;~agg=4$P{U^Q1(JEQK!l}T3nGDA+M@}JRLfANdv?my4iS|qp2 zy-mJYCKWp?R_D#OsvUlTcTCRAJdzRP&f(nm-e7Cw$M5{r&NhB6hGKd8`#$m?D=FDE z>%#10Bi#w>+*9J$e}A0px6@Bcv@zAaMt8U85ecaw!ZHrR! z$+fzT(LA#r7&q_BfARjGQfn7mifZw!5AVgVyj(t^DdHN(43Tq}CV6HWr2l!AliO?Q z%h}R(_@L(-znei9Ty{8gpB1WG@1W5m=riMfmfzdWE1k8a?L+J)wB^=s+j>;%R_@F; z!%sYn-W#3w2!~ggh}4A_I2TBdn{MS$Z)?5cU<7UI^wDC{h(9pWskBK-Y=?2^Vl{0 zL)tOR)otgD!vlW&sPks;_KB`6*M1c`GknsO8%+tyf4Xf-1p%vM+ z-`C1t{eJ9@&62p(qRC7rU3c?!d{&&d`m)xs1tyW->!Nf-jut#GKbR%Ec;XgWrc&t` z)v{e?jyrwA=b0?Ks8VxiGpFFMh}x&V#>#hRm2t+r+at1NWil=y+`3D_2*ZydeUL#{1`Yzd72I>=HT@k_rwS+IZ;smKj}5H^d#4 zR^Od!JU3)^-qMvz7M5@PX6>kVSE28j=YnRn9a079Ef;@|3~=%;Rm@CC_`WuU=5Wzh6V<`paMcrIMHN8vodl*`#_Q zv3+-_px2L(o$KCwFPLS|o3?K5eUB*4LsiCltG|5~OYCMSIk_cE+b8$yhNU;Y)s-C- zT*w_gBboE}sl~GE=gsDxb0N^9jB(|sD!DbbiUo&6yl={ye(?SiAmAT<>~y-&ch2@* z@>7>iT4S_!*Zf&(o99OI%$a9)L&9)H-InXpO&89}sOUT9C&omrG|5=>!b)WS>}#uA zMLyOSb$xHT;^Et9keN2G_Q?u+2E7@#TwY7syprEMF_eK%@Onz_;$XFjf%=mcpPJ0z z(Xj4w)v+zlE>4o@eYf(v>Jp}dzNOQzTg*WEw(I{!u3yhRZPIoZ4yU!M(|VQiwjVHJ}~oTl@po#(ffD6M#w za%khq#9vR6zvK$WT>Mqi&{ih8YkRuJeWQil%wd~$-tJfw8zGh6{MyyNcbVKHX0P^@ zVO2J+_Lr&_Ui>w4efO)Vzgsswi#4&SZ3_M+_%-W8%6BcXTT=~=E>IIF;|kp~H|#x+ zLi4^2ojcENJA6Ioqut?<67yR(r&|{|na?rV@wX?x=pzT~{%Tllr>K+?OAl;zv@EY`g;Coix|_o~m5jqVv|qNObzPZ`ZSY%cLX-%Pb& z_vgUX2bE`)xtP8<{b;Um*Kg(Y>g%l4K?`@g7_GP=uFJpf5O3^`<3Fr^XI{GbVbgW> zmnRe6K3x*A?O^DYDXxzubj!MadY*FVl&g9Fbn)^h4`;I03;ymB`1v(Wt?l#fB~IHW zdrrNc+kD;rWTdR~9cNk2AImSy%b0sR)J93AQ%wE!j;C|hyLPu<`IQ!CAeH0G)tNUX zZ|VjcA^R}Pma@q&9%KtEFR(}W*m7&1c}HC%jUz=LHHl}>+;(~I;zMet4`p4}^WAKPh8WOkTt_^>0G|oBI{*6x7sm%c6eQ|YT@^u{(9z)cAX~wHYP<*-}i}nJ0{q# zNw(dz)LxnIpOLZ0huyMkJuj-fZuRkB#F^_Jli&E!Rx#~c((~)FtJpSHZQma_|LB!D zM~`j%98@;*U48PA*DVYej2I<&4ObRNxjsGH_H1XywM9|aPDvH(J>^?+NI9kSi>0Bg z?T3wDrMnN^@#pUS=~*J|@+v!_JE$h+muSi!ABW=wdfCek__8dy_;}IUZo5gbB_)@V zKAmn>Fv2wn|{O^{g9l^M7nVlFW52@XiSfW0Jn7d2wPWRG&Ueb( zKVL2Q6JWu0ugZJb`GXVrGBn=i{jd%%{B?ynMM+F*#goo2;Fbu|!gQ#hqPGr2`#= z{=ZrB_1Fs5hsPD=8FSf}qyBKU2acHH9)66edJiYpFOu2F7Mll=ji51W0pK$r$e5`)g z3&(?w7P3!wy<_J+Huc}SzRjO19F<;`6|~%m+2l3Dc=g>%$Ec-J^WxYYJYtv^F+0BZ z3OTd>ypd`BjMf=@W~#|-i!Ic-SkMqMp+T8hw&X0sws{)XnFse@U;44!t1)Ss+hzWR z&#mus-S!oGD<0anC@yfq>^DijrDD_rH)q%DvgF!?iTk##T-i_}ob%Xj*~OWW#*UV4 z0j^8KH){Ac-)g-Xmag?@|B0R4auX~iuWHyn3B079+*$F%x}-4b_9nN>_qUfUeBFMF zRiNR}kAj&=6|elC$}JBu_ns5N7#!Iw8)_W{9yV8Wqt-6J*pgXdSt*OAs_-OVve4Yf&9wDVuUSW` z-?6Ri*1pr1-S2I+xiGKmj)r!T`K=>@5>Y?iI2}whW^q|P%i@J|*3|GTwNepW)2u`c zTL0|0WVA#~cAkgy(i3O?X#7sJvi>-2(j1Y}7iR>P{kLYH{ZGVP`f7WV(T7R3k(q&9 zD$TqfzR$SgsaZd#^zylNUS?q@jO`~_&A0fzLMQRnpLd~mCfyPaTDLN0`5Hc(;J{o} z@yjRkInE^p3)LOX`@He>lD4dm`|lszx%XDy!o*5*=>zpM?p6i{tWHTX=6D|bb;h)Q zotH~5ZTV|=clE@<76M=0i{cB8*W?YoQ5>}{s$KmEG8+pk)#LCLg$ zIc~l(NBS1G7vbu!v(9)XeBBm%Y-{AJlWn!f-`#EDV`@v>5OQKZPve%eGZeP|moLhH zb!_ABIs6LilTM#hSKpEox9zRq3fJ?8c;r@OEw?${TX5d@W@nk{>%hITxptL{&p(ki zcK>xM#JumI{nJ~{7t&p=J0stu>de{Sb$k``-)zebt_sim{}~yrt&BU%6!re+-??nY z!Rd25dOJO@`UzXMnJHefzqi)#pgLpC)Bl@|6+U^q`~Pl^^P}hA?_OEvcv@WhnfdW& zJJj;DH=p)6dnetAZ=>4jos0gzsx{I)>Hngk>|e2W()`mwa!H|VOICN8DHV8c-o&GK z{hs3k@8zXWy4Tb)yxxwgT zls)F_{75*I)zil{{zGeI#@YjR&1yEFQ1x92;vF`r3_`{<{wA38VIec8vW z5v05+hbQCIj&G%|MT;w5pXRx;?7{s#meT81D;wnohF{CKl>-$dM=Kh#@HD6C*<6@gFBByPWMc%k;8y5oxa`!jPMo_o7fu!85p{6C8xuH0%K zaL>(N;$W=TnOCz`EVy*1kzr0z>;dy1?(=Wgmpi`MJ9V1iZ{1R-uU_&O{%G#G^0qo( z_V#=pL;LxP_Ps?rz8riR6h2$k`c{}lZnfqd`zfW%G*hEf93JGRL@(RzH0!d{_x?#o zP9}ZY?q^r^!s_>ub%%p)8F=0E`O|rE{j{d14{q+AXSjZ|p@i5wXC>b1W0%dfclMsy zuvRyraZiSCg~_JIv!DJbTzamY7t!?f*~O4eJ+3K$4uQiXBobp-hN4ufj68j~Q z-m~XAtCiV_S8(r_-=q+i;%9S)y z@+(|%HG1>QqizX#8$@fkYn(*4HP0?^@kl$oYpSr{vih?kibCW6e&)d`pdf~`yEU1%=0ngs~)!TUd^(1(%v8y@3YXoOnl9=-o?cyGE#%S z_=z(Lh2Eacs}*`>Le5EE@MPnUS;Z zRr21fStk>Zn%)0kd0JHW$o6o7>PZ`yr|Vd%8|Y1clCOU`zxqJXqN2v6lI*zUH#GW{ z+H|vgSFbyL{X}rfv|Fd1DrX9}hQ8{WzrCdGo0#Mg&n-b0xm>o~OV?y6-)@p0`CujI zoq$Pl`?(G68>GWzZY2awIkuyjx7grk@XR|R3mkVHTkGVJ@k`d|(K6e6oGM>aYOgwf z-0+&}N9Ys$!B=%gcKD+YsjQtObFXyChIwgK*|ICJd*VOO(+OB0Eis)CW z^ZF~W_TvUcp=6QI^Y=~HjIvaewU2mnSdqVm!M0$tk7=FS;`1FgNivgqXB$XdIkatc zamOi9vwyjD*83GSHCs}yeD&QW)A8mp=VX;ng?Z^;zxc*U}J-GsxU`!4$2 zWPUyEUE!RSZd2a|bq9R5$kml*{@f`3uG33k{XRyP^wej8`#mx{pR^xR6%f3AVou;L z->JdpH^xq=R^8y}J9&TfWz{v-tNjg@7;WF>=B_wX>(7}7LQDzIb2WFHd~`h@F>j94 zrYg0mtpt$A-C==>jWAx-*m9#VS>-W9ORGo8r z)3=#zU)rJ6d{Wv#a-v%ar%zk#q|@u?-rkqcl5+CUlCq=;A60bHUoZOA{OH??k7Wv} zyB2g#oyW-dGNNvix%yDhl|!t=lptWp2IEQO~L7+ zIqX4azH?8Q%e*i5&EI*8D|(K6`Twx+;{~p*Q7W19**)YA-(qFBpm)dX*taJ+VGVa& z4$OY#@v-IN@kvHp9!FH-8Uo{1OjJn{sXC)?me6o*t9FsFl1|sN*F_g+#M*e>x_jwF zSYt*aFMGGu=`xMQx{~bsK5yLC<@Vu|y0M;8eZ_-c0JX1S?sxN>QuEtAT$B_GyonxCw+#43O3AJc|( z-VjS~y(fVZ&CzDo37<1o%({Q7(0i%;j9K|gW|pP9 zY{`sY#QX0<{e`1W4)@j`DA50OWTAfPj$2>nFXPkjxNg?3v-bhRL2LGgX_{{hW);(nH z!F1d5@QKtZfAQR~|9Z?VM4DE|EuhjtIHEJdg?Yq!?V`pyl_q*XR`$jT z*YJAJK1-oBW$Uw?G%ss^miw70x##_zr%UzgHecTpt-0;%^`*rLy;c9Nm`#5*ulLIQ zyZ<95+e9uYF$k?yF6!UrK7tVPD0`^KJE$e?7sh zzBh%ful>EK8D0PTM#1%)ccr3^u;1jDFF&XiQsg$*s%7Roxq>AJ;?3W-x7H`dcRr10 z{$c+;)NZBfZso6mOrBq~M2;-Kb*;VcVd_k|q}dY}GoXrG^0abdLF+> zo%B+p_vX1nJB%IuelPjLHg%(l9%EtSNu2<}L&uDFZFLe_Sh0ESjgOC`&m~oG_*uq0 zS-9uK{k;;_ukS1<)9(#y{_}spN+y1w30g(bldcly^X`+{ z*4nGD_J5R})^q01%AR2R`CA3Lx}6W?{f`ZuH9>PS|4)sX`IGlNm6cxd{rJu#w*!y% z`qo}wDf+8qM}^PYZ%d1fkDN`KdCFd|Y^KD0u|4d13g5f71V?SwdaPgVQf`;p`nyMD zoxSl^!HheSGdfR&RBTO`aQGY%89ifp%d*GbYr@{wESB3i;d#=|Q^#7g)jrK^Yxm!D zy-eig#(=%PQ(nC_?_K@Oz`^bjm&pB>>ZKnqoK}%o{+zu(-ZDy&gYVi$H-qYR`pE&B z9vTO3O}^(J$8)1C^t6riitVq}i__n1d(YmqFW_ID`2^NC$1f-4@NYR28oTpx5rbtz zh0OO&p?bDW<%uEI4(Dze&04)sz1!~HYTval8#{H&u9m;pTO1^z({R3OWOZV*GF^W8QS!o=~aBric`&99juOmDP z&i&$^c;MK2Y1OB7A<7O#1=_u>a}rW7&o7U7Z&`7sq_7}l#u?WCA}eR z^<6UiH|uy9EU8;|?&`6gMsaK9IlRxmIMlNq`Mi5xaaS&PKa=8t9j&}C_s9JxIA6T6 zgER58S?#@f9Or(ziG~ITE%w{>@mXqg`qAlX*;+gwCnaw;uMAxmx!gET_syd2^3{KS z+273TvfFW-$#|i3*vh{hbLO9pWK#H3a5?=}cmMfdnH=5c$LBEKe&Ddzw{P6qN-_W4}I1vkcaG&;Ma1@-(jO!}@y^AxV z@-+a}bFZNtD`s&CK zst@+At35lY znLoA7%Y9KovF8@Uy$7fAr%s=B*T+%VPhL5!bkF;vHUhFzD;3vnUle}v9*3=?Ipt=6{x5#}|M(>rdRy=RkG8uz8{F1D-tuQ|c|-B;?QY*T?4PvCDfHxnr#bu6^Ag`= z-jDys>0`}gv@IsPq}=#V(DP|QyaE%pX)p5J(EV^3=g+PU?m1uoE_pkp>tCMVR&$!=kKGC%(W`E$A2k&nCw0$oV*I-$F5I!?vvi)dnx@R3C!3|> z&nC#(ceZ}z5-h$V&z8UK0!y6dXP!K!&)pecFGU@^AZIpL&f{Ee*2KH{cii4YYbDJQ zwcWLJ%I!aU&aJv`68Wmc_jUN^_LynofHdzIm~GbZI1oGu>EEqn{uU{cZ)n7>~3Z={KywRwf6i})(^4S z7pA&+yHrZP_h^oJdZfei>B7uIy#4KQ*$n?TH!V3grSHjY_tgQ9#PXdz7pZGI#b-Bf z|K2>=x8tYzs`E;5M+^%2Qa&}#E;cQZwRT+3&v*04J0Y$WW}Oa`z2@CeJs!`nTtCzI z1XFvrknxc%98*>Z&$quiF{15u%)NDQRf?Sjln+mj=lYtdbY00{Xo(=)AB!?i>_=vv@k>Dl}2CncLjrEKUP)Wbzh)h zRQ|74NOnfL|Gdq!f6jc>?ziRa$IrjpS(wF{igiP^(pg&`^rp+%^_%{^>iTQ)z86^%={IXPNZbLEUx*Pq<@v8H{)JFB^} zr3a4(PFs>5CAM_^nQdq9|JK$?U(d0@zWA=?yx13-v$lMCxOsit8a;i-(jht8r|bQ>HLR90w!l`YW)-z{Y}wm-#+n;rn2H*hg74E)Oub|`Dv*Sectfie)g#A z{M_@aCl_z&zMzsgSyJVXqv8j?v`6KCuI&$x`LpT$#F|U_H8zipPJWCLPWoPb+5AGn zX1i?V!cNvNDlVHeyj1)iu(H1l=hXc5b$zD#=}SJkeODL+A7?YWYTsHFb*W_Ymz(?6 z#DrFFzA>ry`K?JQk^KkX@3s${&F%I+WYf9~S-bDtK}${9Y!~(xAOF2lWWP?1x5ImF z`5z4a7w^x^x>x)#P1AKUugTe$KTMggcS*-QZf5>`p{+~i`Aer`o^NU;BK8``Zj9e@ zrTx9~TZNkZf;;niZ;JZsWou|P?e)6)aM6S!p(jcEOwOI_ZPdGQ-}u@(gZLn^1oLe9 z%>6fuUaV_zHsEFodsn5pUU|X2)BEqSTJs4$w7272QkeLz#0U1-KbJ;o&UgD?9-0_utba}>HY34ur-13qo=D+MY%U*f$$WIOw2Inr zyUC$Zfwg9;^v%cH1S~%mZ(VI)yR3b|m01@TKk>5LEU&uVXpXC}&Vu`q2@g-FcR&7F z#cuc3HsO_Ro=$}3MY+@L$2y!}h%OCekdwuJU^W1t9&bszan`RZ0lVFv6OHuKgUZ33Nd9EvZ-fxL7`Q4gcJ~v0~ z?uxw}4g#BF?|;%~%2>Q>!-eajnpOderA4MxKAWuguIB6QDlr2ijNW5&&+*^;!}73J0i8yX362@a~`INKkfd1JiEB;)|CcV|E!MNM)y~L_;O70 z=#1A9g5_UU$J(fcSv%dG^m4)P2h%zauHLwKUHXzcpI({n@)5RpYMjNHm-$_PX#!7K z<|&t$*=bi!KCk%basTO|r8P#cAG@5Jz3|E96A^FDW$fI{(|2p9gIbELlPKrJ37?eC zCpbPop3fV7@6{urg$pgW&VDDf(4^4i$LUu>X2;r}Zdz~)&Ar%ssGb0 zzv9{q!SmC54_r=hm}#(2A$GddgzI&i_}(pH`Y?O$uY0#%?7IH?{7FZ{xZveok^h!x ztaamV>d5N8scGnZ+gG#4K-JIp*}Jxf*MECEaT#TEbGe3eCERcd-K6RCc;5%Hs7-fX zzc{^A%x2Dugpl_ua{kMN7rfsgmvNlWk=5_mrw})j8L{V#T&H$_G2Boz|4Jsq51-e* zoNvV&mkG424|+Xw)_2YRziq$P9`^c^qm!dh;PU2@WEw-D!=DB9FIOwMrW@#-oWuR% zjW| zL%Zg_BKxAg<0X5RdCrPc>^|}4x%kq@tJ9u-XsGej56o0j`;%oU#$^2DGe@hX)z`rL zPhWO%oqFoFVyfiDOfhBU6fY0wPeSq+E3##g5lJc)}y&+YNj^-U;ciZ>)k+i6Wh$FO@hZZ z{$S%+^IBukq;~G@QghEP{U-OPUf%dk?4yZ4HIvi4E(_N05i@%bC%>*qd%mUoJee@Y zDUD_m9*Bjr961wqM>dyrw}o)e=ZCAkI+yu!t#-(7`pv7IY~r8Xx##oxjxgC;llwfp~uaVA>%QcAZXj~`o{#cKCL;9(sjtuec zz3Oj-T|S>Sa^3bYW71Vc4xIa*6zQ}D?j-6}{J^JJH zl~?@gVO#D@lISkJx-j2ftA5eNM&?;IG|pnxB4metnMX zbD8L)eP3ATFxt2ulI@JzeLCxc;)AH)GI8a{olhh?Y`s->H<0r~gnsuN2bG42OuTGm z(c2O#8V|nXGoCf|$8EO5=PtZGvQ6&A{^ohlf179C4c#F1NV0e*(;CaTmK__W+N_Z5 zdbYYaH#X3dV}1VCIFXnct2%#h?B!}3|H9NVH>td?sU%?fqjuSHw@K?4I&fEfYtxL=Hoo0B zLsomLvzf)ZW3u(^A-gzc|7ZFldnUCw{Zv-=-I?n;RMv=g9NIhGX#s=m;Vn7gCpb1} zpJ%x%oA{dhrL?thSpu8mwB!5l@UHqN-^;bxe41j!ZU(mg1xy<5PZ;DL9ozfk&HQNx zjJPwu6moo=@Hyv_bwaCFiqy5Y{+4evZeD%ZY<2xW(NcdCO-rlP?yVOqGS_^p&tN*5 zC&JcQc3o|0{Q(YV<0n}PmyW&QxjfZy(%QS5xBXom#gO9=6!c5zVfOKgnAK)Ia}zbU zF)t~7&0oARe(v9%3#~6gPFS!Co%X^#jeLsx9^Q>acVEVV>$(i$S z^!F*48>l@<2%E~ef9V9X|G#YSJ<>D`Ys=Qg5j>Uj z*~dck!&9fEPrk>~_OHr%=N@XlSl=o9**|6dAJa9e9!slE%$_J6sCngTv7CX1O|H+x z0OeIHCs<6VnR9pBm-s_h1xs?-4!MN1Zrjo^g~ciNGv^iuEAxkzTTUiy(=%FfIdW$& zo6lv%)Bp9}CimWPJ|#J6>ZRS9JsBq|}Y6!VDgv_a`ol z`*N@2<@N)M6!=ROHu?0JKDgaFnQ3P4{=79yq}H7bmh6-X`5@Zf&ga5lxQn4}Z_rZ5 z1-)(xkMoaxePF|{{-*2j{#6U>LO2%--t7u2RyfGUnNqtw`BCi58JmocSH-aHYCKx% z;Jl&#_N`MY2WEI=IWx$%zffBnmerS#-TC$`Z&o$i);SkzqHL1o_zaD&nakb2=%(<= z@A=K=uOr-+p3LTFS(AO;gTeDd^UF)8D)rtp%kqEJ)RAX=H&c`~CgNASjs9Z}evP}S zT%SL;brRI8k69ZXK)~7yTumB)I7W5(ZA@T)yL4% z^e6j78iE>fZU^_vS=OoRKk1Y)n0-QeFNf1vtHh!uwe}9_vf{Sk>2as{@dzBl}vgxSzL3^ie1lqQue(+^juHr$>iLhX?GhBM0^WTJo3ATBc0>+;&nzm zx0LPw8nrR3>^6{=`|7|Ubd^nE!@iomM_kgbEqNq3d5u~t^Tn?ZWe&XN5=@cyv(V(6 z$k8Y=lgs#Mw6OWL;u$}VOuKCn_vy-MErYBTk=ymRubbVyWB;4?shgix&nl2SEFr~X z{3!j@cgYEw?sfsJ7RO!NU;f)9@hd&6z{U6l>zV^U)vxA6YnbXiw@$Q~GF2(h`m!PG zt*}E`D`%~maP%rymb&o9$=dFWEUcv>VwraFo-W7DmZ%8i^a{B0rLH<)_)~qtLx-Kk z3l!A(q=OZMvmyeP9-Dh0vhe4?F(sxDLx1B0(EnVJl ze!5%e!&SxIMnAg#q=+rw%d+Yk!;8O{qvv^D%WXN{S(g1IyF#iwZkl)SZPsJ@(eexW zYxvhPeVldcMxNW$X7fdlHwm7aQT6}A#bdSyK1km7aEkuz)V*fg!{zpSiZ-s(&8vF9 zXvrBZ?cFx>E`43!l*C^^;OYgYL%?sLp7Z}%OZ0xJMte+5;-Bq zwdvc9g;%p(&Tn2=dzSfdn8m}hEP_3Kd%M~z{pQ&hc`x~LyTSF#3rC)F4bya3qr`cb zYmT^WlD?uox1w)J;EbvXH7yhR94B^IEjV6XpJS$T%zR(X#om2wdJ#$O3qQ#&tuJfZ zeJ;q|>ao-x-;E)v9Yp7zAH%SZn3m_nCLAvAKOmjE&<` zkFQy8e?NZT|6k(V@v9>Jawm31nPsMaS>)XDtD!dWdi0;vK>y0Wd!|J#6IT1Lz|$J9 z5^^m>m)mdm9;s`pLjFDBBC8*KyJLRl?LKz?MP_PMU4QqS&aPkRD#RAEcF7g>+fOAt zSa0wA5q8z(#D#<<3R4W8@rU-a2-``dug>jn>(PcH2N%vf7um9jG zzk~j6>q8t_4}Pd-pWFU&=4s2va-aU!lxig}d&`jGv|LFjE>OJs&l*nie_P5-_Svl2 z|6BFSnOUo%m(93+SxA1CynV0A_Em?~Z>c(6O8VRp_}lr$$6&$2sZ$+-cPl4}h3vnqb3I|* z2!9_&6W`olp7U5Gj(#;=93Xy7@PTvX z!f)J1UWvD9#k0%qhHFDdDIG`&Q+B(f7X}lw8+lJI!9Z zF zyuKZ5uUB|yD+Jv+uE4x1 zvfrP)EPkosw~jUOiy^1N`%7GXf)6jT+;&*>;{Q$iWSy;z>i=d`hqY{#U%IUJ!a^0( zuYzoU7Qea6dt%b;nk;#Sz779s^{xnoUqAc%!?iWX4PPHS(yuLGaotv7`RmXBgdfco zjP~bS&N;vBLwedS<23H8+h6HMxr3&JGDp1Lzbc;bC-e9Dg{EQM0wsNx zuYSh6t(CjBq=NfO`rR$l{(nrkbS$h_czc_we%&%H`Q+b@`?Yqgs*dD4^!60f!Jp+X zdM@*J^m?bUMp^K)h<|=@b0b5zo8-R9+%>bNh0K1;Wg-wPwxY_tLF8b=^@VzOlP>BO z-#wY@w_uy;|A)VSdWt?$ul$s5WFGUaI%(k!nvum5tI%hXA zR_3Z-x8GM4=4{uG$uiXY{J3t4BpYM>b;iHfyg3%0@9UlA{_C!H)`t@rrA*r^`{sS= z)(d8RkkHA`r>M36vC59@uK)SvW%B~QZw>Q1{f67{TxSXMR?%@bD|g@Ru+C|@qkg#M@Yeegjty5ntU7+ux;{t#dSLB@>-G$fLqay3 z@#b2ZJL~ zd!5hZV#Ni%7e5$p2maU{_ ze>tsT%@VLK-CwB7^<`_Rj(Xnn=*lMzN6~=$g3^$ri)JMWk`)>Tv*CJ zsiEdm^@^#I`#Ts6PB3+|UuCa+lU-lkTkxdU^tiK9#maTO4vHZHVnQW%%|$LQTE2Ku zj*(tO@do)>e~$CBzgT;@&~C@+Ka$f8Sp4NTaW++0+)q+`c3ET5|3j>wZh7t5c+Wu0 zIrrfQ=Bvh?rHXsJtL?s)9-YE@fW_yz%GraDczPIOnRk6#S2%r7;f;kBw~HH}>?@u7 zQ2)u|_e(FfZPt;A{_$avG2_{V$`g{rC0_GR|7*QBtLNcH?H5inBK#|vk7vgOXix5{ z5X?N)bvQBI?c+V~m+MVV@iB`AYor`WT74iycI6_CWh_;4(@(TY*V`Xr+8o;@v^;gm zJn7w`YZyGA`9^$aoFy%@WzzpcI;-8()_82Gd43|uE|ya_?u2nv^Okb&^OtN-w=1c6 zZCPNo;_BfiKRnoc7+P89&)T(V)rR_0`&Bak9qe~sFUURdp1fUJB-=Xq&LV63*h4~w zFE8_$%Ds2-jT2Zn&oo!wdx?9qMrZ3UqzPm-0baF?I2QXH$%jRP9ViwhS1-r2HZ!}R`ttp6VS^M@Y3;23(O-<$Q^ z^S7)M622PiEL!6gF0?3dS9izb>4UxAt!G`8ij$ zbXn1(o1FVUceF7pPFNzq_q5O<_VGzvy12CH?%TUb?g`Po2QM6- z)I62f*>cS>mzS0=OBV0cG%l}mD&W&@FWDm?_T&^teEq5Ic3E#@e;%nlWW zPtiIUAaL9FZPSJV7H+}9DO&{7Uy3xIINIgHisGJl&;woVk`o&KaxEr7#(MwNkoHm0b?*y@AZ6oQHi*0IT!JdG0kcvMb@^WGY^ zX!bn@6<+Wc|-QDZO(yulW9b<~n;EUSB%v?4%$l9HF-@j??$bC%)hF-yF&4c+5ME zfA^)Rc{jhzyVb+Zw7Aun^J~qYkcZLNX8jMmudBYXzSHeQ?cu8XvfCYhr7ickd8dEl z2C*euKg7S;m)AM1@^i}CS@%{hDagVBn8CXFk;CEsi-@wJ_mFwOUTp zgu@R$sPM%YZ%^W!zNo$Gap&)8+a_3VU8ZbN)bW>9?RnN0or_aeIdUKA?!243YSH_J zO=`P1o#ie(FR^Gk6C-_fE{DUaV5y8pzmD;}y!>^~fk}-%3|Hq}{G=qYX<2Yw@4BKp z$D%@?hC77l?|72J`FW|#ott5Xuj7Otgsl5$Xl(D{+GO1ncRPbqd@ltt3Y=YfzDMbVMqA@P8~?1US%#_eY|EON)|Fk>JHGgZf#1ewyvNV4 zsmk4%BDZb&uhUVBwG4k)R;Ij}J$qVe-_pzGOLUqpv6e;)Ox^DgepoNdQ}f@$)I&^* z({|O*J$CWQUZvC>>Y{IUR50tE;Xi5e{glrshYm|SIO%o^RBS$oE^7!+R+=2etC3t=_T=O&w75R@ypr=nK@^3PRQ%Y zESPTdq_JzZ*38XQlC3r|Xs6b-mmj(Pv|N;Dsphk19A4VNo?&&?pU&C-=jxVW3}ZMc zXSVlT*TJybhT5WC53_ zqs856%b(j_Qh)7zQ}g(7nQsm~FOR=_>YAU@mfjJ*|I*p*k~>p>giLE(YoXNXS0K#s zcgfcKhFoiu9*S14Wy^aT?Du#|`{!-do4y@9^G5Y^<&E#}m6wH^$43S|KYZn%tK)t>j>Ianil{E?g2Hfp|Pib*-Ntt@Z>!wx~` zioZRZ4v*pV_Z)j9>U&GZ9X=`+bU2;)>u#ZHT`JtPEiO=SpZh0}g zP05_&@~=Gdd zB2UTg&5IYmwMkC<-ZwKc?sLhcPu@@aj(!kZyW1>oqdMD}oy=1llcax!uRbWrBlrG- z33uV%vq$EAk$o=mP-$%_o2k-K1}E+ZZ2u1CZQLalE^yq+cwUR6{@)4rb=M~Uyk8qS zMdU|Wksc@S?zvb0isx_AOh3Ja>+AXYE{@;LGm33jFy*hC_VU`h$(FKKdrB{`zIfPs z?*&&vif8xVtC^2?W;5n7Rt3#suxb{O`zTr_`Id+O?V+Z9wXQcJZPE^jtuD+|-@QRE z#_E0?11^zn z*Th4bmrQ?@b7+B@yRMk(kB0^4vU>PpPh8w^K+k)MXM;Th%kKR15l^3=dl9MC{#&l= zfzq^HF}f-?5x)y`H#ZcVU3)~pM1yUoPq*X2Pd=8sC!!uLn3T%+UG05Ev765p-qI&d zrn;_5(@tz(uzJI>6V{uzFOYb%`NRv3=6A8ny<>Y-oFqU06Zo#tH-FiwW7A|9YqPh1 zvE(XSx1!9PSK4HqnC^@7%WJ$JN1dOzL1&%TqJIr%KiSRb5GddB?(4NJjU6+UGp;%M zi<~>gy1rzes(kzAdxs~#Q`ZRbnR$J+aLEtH9o;O-A>n6V)-DN}`RKxJ$ElSSKNoL) z5NY#q^QonZZVKP0bUAPKFSE)^Hk^5(ZKGMfUS!p~u*s`;T)iA2Q+wT>;beOkpOZtE zaPlqjwNr(pzlK*ma||w&i=1*SCHVgYwd31qpN{eX3On=BhM85%jl|1>*9?US1&t~r6cbC zHpbwwD(B1YglET}FS%Eke0K6JsWQ2iTo`&XZf z__XCri1fEDOMdj0&DuSW7;!0?fiu6=VB+!tJ(MQ znen#{*~Xfg{8O0Dp32|G)~m2_{%0oj&63(uKSSq6Fm&_2on&+?*fLC3Q}NJ@8q3+o zTiQH!Ho41uUdq__J6(FCo{_Qqf_?nEJ~;~BcD%Rh&Ig0O9hz;;>o%_akzABI)zYr( zY{_xM#}5vL>~`kJ=sDwM)Xu^vz&O=AXu+2C)g3NZR+*``{#?s(=%FRkrKinV*M;sB zDoDNkUE3mkdfJ+hFFPjceSRg9QthkX`u)WNzPkcb7QB!4+*PCzUmh!C@_d0<-~BIK z?;3jg@40%<@-Fsz>m%V3RloM}f^Vv=PJMw3D(CO!wEb#%fmJ1Tp7zg8`%5>*o_s!S z|H*fICSNy*d$rilA=4y_gL|UAZ(!-`&6Uqz8y;F>e#}l|f~J8DRCJsE2>X)J>gw*Te)XxZLf*ji_0y=8=1Gu-_@|U6qcQ` z($jSJ9bBh@}66kR{BLROSYxs$isr)T6r0L_N|f~ zTY6M(nMP>6Z&=p2DzuzEcOUb;vm0j2-)3Cld{f{DQ_QR63C-&n&KG+w6$(w*y7y7) zx@9*#WiA&vX87zcdjG5M#jJIw6L#s&+Q62*JjdNDKmUu^Isu_dh3gBaF^FtGVEbJ7 zUf?Icds|k#?w-8*o9%JWT}*;kJ}jHC;V@7A^>CdfTmStMw33-pov68OW5;g4Sm~P% zE_Yrm%FKT!$FnguC91<@()v4`yMk^#{K#v+DT9}5o}+1`PPOq_$N3Cd^A;Bu+r<7g z)?TyT!J}P%>CXup{)8NQa5~}4GG4aQ3u~QjxAk*xn)*g8G`) zbTs_DANkxXet*S`I}OGsHvcGIA}`r7o6oTEda%F)4%gUqMza%d6o2`De2>|QDd!xf zPJi1hley)`^3%#S(*M-22RldaexN!1S?AyP&nh?#?wsukm43424ZE(su3=ulo77v= z59PQ!7kO(0M_%=|m^1l%e<91&DZANaf9C&43CVI%J^8xAzID;2Jw~m@vcFk&?tHWK z=?100XFl7i-1_?We&Z(zMQJz2lmpzYlSM2RZ#mH7+i=GHlH3#Lr$M(%K5x0qf5u96 zL920hP@cuXNxv#49Adg)7d!7@!%KBh=2ch2)L*aFy<`01%*($&=C4-VcEdPRCG4@} z(V%C)wyG}foO|yU!-?fGJ*#;C>sFk2xz6E<>$M41eHs6`OqEb5-Op6dDJ^&*n)d0j(ZBs& zPfpxbS?!^p{$gU#F~`3v9(x^Ac;CRh`*ARvndz(rocrpYhyJ*^=+Ik*4Z+pXla!{o z+AQy#;h(l;yXD;}wab}~`vq|JCc6qNcJe>W^7Scwdy;`y(CN+e{NR12X63V=ZgTZV zRgzp>XS~efvex_9%^I5jW^y+Ro^Y{r(^uH9$YoIV*kWzlq2(-5`!3x#7V}Tj={d#P z?P-_b<~8p`9NShw<{#Xxr?@^_zP@={Yvy9Ezv3;k9PAwBOOw=Abf0d%rV+|5Iiq|! z-`w~#4ZVpPDspMjbHC}xIdAmXl$@H$`z$Z^?pFa1Z)u01A1Vbea|%xEncFl)dqG-G z{@GN99`_9y435qb30$9cVvyv=fv}uTYK*ExJ%D?^Y`xj0H#OtH-6;U z_~(Ru`-QT&hCBR+f<8>nV2)HR+UI}oTj#P#r*h19-q98MRb=z-jJLCZywI=dEoLWn zTEr@Et(IQP6t&j5okzwfcD7}8s_o$e@pl!@ZoU2FnQGq+Ej`C8D7Z~6ok zyIR#8Zjnvx(@q{)V)te0_UTOg{nsYS|KDHG5~!-`6?5*I%~p-wOd;BtyxUfpJ=nK$ z`_xO>$L2Fi{^g%>`QhfmSuYD>e_UM|U$ZaxuV&+>M~Ywa_D}U*VX<8QRFZL)@7-es z!Ewc9b82_5?Y8-H%Q@_eb3@9Fi@8c2^QC1rpS3@BjKn}%^=}-g4KDZy`2irML)6jO&4Cvt)C>~zt(i$&W+u%TS_~! z?#1+Ps@WA1d1q=veB80+A@v(NUNqe3Jw9ooncUJ7%RZWg&d|TkS$Fq(U(c%*T?YP+ zORpu|`s8}H@VE6%<1J?eGUh&S+z@;A-Tb-DUfO9h#NU51ZmPI##jw3XF**3YNpzln zN9dDw+49?_%)-Ym80Xe!Y@PRY?E^OL3kx@Th|ajgHZA68PrQ_dXVTgqyfr{>rB;2Q(BBKe7s4`T z@@}{wC{UIBx7X>#jPHKOr#*gQbuY?&mDP!jSIzSn|L#$aSk0~YX5Ip~52Xpof38fC zy_6!bafuJ{nXzhC_!|1ADd52W3l=2^H!Spv@)I6%`ZwGEOOAw5_-+K_xNRQg;%@WpNKHnGDsAzU}p7E z4M|#3B)FEf;c~{e^RLCCCth}Ha`%3BE>2OeCA#<6g3E<-cRam+tV`Zmd`n%A`~n*h zyG84oLYg+;%l&j_jpO^JALL@uV^_J_ zc1!T5f7bB<32d!PYL2sRu}gV)bedZF?%yZe6Bk`7>sWG}O~&=Tgs~B;+`pNN-nO#L z=+R)B$iV8B!&^Fg34@62l}nmW8)VqO8_xXGP*oUN?>D>k%;EO${l~05ZND~VMs#yK zPTL|Mp5hPnhPTDA8{e@|HGH}Bkk+0&Z;-=r$!#CbKH&Gwp}$tQbrY4yi%!RFGZ zEo(l$WV~E|El#YDE4K9Va=v}@`XsI<2AjmMdE$EJevDcCN0mdJ-+LC`nfzqyW(StP z`MH}9L@LDrbuL$|$f^nfC z3stNXJ&$gWxs~U5WzN}vBHk&XeLk(<{O9@bFZHkIb-T&_aE*1z)RnT2kEklO{#@n9 zy*0XDH?D6j_qJ`V&zDs>ePBOz;rwo1O@JrR|69^MgH zp#EdM*v74e(r;GTdKbKuUta%f?|R3{&%QrXkT`3exq8hG&boDaM)Qx);hXMKyZT!4 zmZ_ST#9o+r%I?Wuz3FJ>4+Dn?-=zmUSH|qjZ29OA;~Jc$;%DT1ZQ@D!qqj~jJX5y* z?{poR#@`Ws<$EH(gxx!kB>hWW=QZH<>%wq*aWF+9)Nz3@P@ z+GdrDtDFt5u(n95A5wj~_`Bc@&!rW+%U7E5mPk)J8TNaPdh+D^wv9=a^3x7#9ctyx zeQ|ZeE~}LrB#er3rv7^$+;T^J`KQ;*BbLmN-&N?ss~p|PYSi;8Ao}uxa;}%l7Q0IP z+fb?3bm&o|v6gj2B9)IuA&#?YX%T@2o zYCd0m{m$<(%Sx4(yla@{*Ef00w7)IW(hw)M(BhHg+LJrtzjZv*sd1|i^*(-0=Cjv| zeJi|X9ez^DI_Iyn&dN&GE7u<-t6N`+4-qvhna;{^cYSBwm9HL8Mc8wUJ~>WZlonRT z`Qzu|uyyA*sPeIBg$6fftg|nD;3mnoN3dCUfywK&<_sMBPwOv^e=YdR!7$^=w4=KP z@2=T6Z?(ykfcYOcu&hm(F7EU5OSWa{|C7BBe_Uf1{GmIu;J({~qVCd%B~c8V>(*5H zZ`QuF+{pfh^e(qjx!Memm^FzqiFOVghq=UmZrmj~@#V$&&t$zjIfIjPY?2#J8_nLy I?$W>j0Kt8q^#A|> literal 0 HcmV?d00001 diff --git a/link-ip-monitor/translations/en.json b/link-ip-monitor/translations/en.json new file mode 100644 index 0000000..bdf79af --- /dev/null +++ b/link-ip-monitor/translations/en.json @@ -0,0 +1,49 @@ +{ + "title": "Link/IP Monitor", + "settings": { + "interval_seconds": { + "label": "Check interval (s)", + "description": "How often each host is checked." + }, + "timeout_seconds": { + "label": "Ping timeout (s)", + "description": "How long to wait for a reply before treating it as a failure." + }, + "notify_on_recovery": { + "label": "Notify when a host comes back", + "description": "Send a notification when a host that was down responds again." + }, + "glyph": { + "label": "Bar icon", + "description": "Icon shown in the bar for this widget." + } + }, + "notify": { + "host_down": "{host} is unreachable", + "host_up": "{host} is responding again", + "invalid_host": "{host} is not a valid IP, host or link", + "duplicate_host": "{host} is already in the list" + }, + "panel": { + "empty": "No hosts configured yet", + "add_placeholder": "IP, host or link", + "add_label_placeholder": "Description (optional) — e.g. Router, Server", + "invalid_format": "Invalid — enter an IP (0.0.0.0), a host or a link", + "status_online": "Online", + "status_offline": "Offline", + "status_checking": "Checking…", + "tooltip_check_now": "Check now", + "tooltip_add": "Add", + "tooltip_remove": "Remove", + "tooltip_confirm_remove": "Confirm removal", + "tooltip_cancel": "Cancel", + "tooltip_drag": "Drag to reorder", + "tooltip_close_form": "Close", + "tooltip_add_host": "Add host" + }, + "widget": { + "tooltip_all_up": "All monitored hosts are responding", + "tooltip_down_prefix": "Down:", + "checking_now": "Checking now…" + } +} diff --git a/link-ip-monitor/translations/pt-BR.json b/link-ip-monitor/translations/pt-BR.json new file mode 100644 index 0000000..fd9c064 --- /dev/null +++ b/link-ip-monitor/translations/pt-BR.json @@ -0,0 +1,49 @@ +{ + "title": "Link/IP Monitor", + "settings": { + "interval_seconds": { + "label": "Intervalo entre checagens (s)", + "description": "Com que frequência cada host é checado." + }, + "timeout_seconds": { + "label": "Timeout do ping (s)", + "description": "Quanto tempo esperar por resposta antes de considerar falha." + }, + "notify_on_recovery": { + "label": "Notificar quando o host volta", + "description": "Envia uma notificação quando um host que estava fora do ar volta a responder." + }, + "glyph": { + "label": "Ícone da barra", + "description": "Ícone mostrado na barra para este widget." + } + }, + "notify": { + "host_down": "{host} está inacessível", + "host_up": "{host} voltou a responder", + "invalid_host": "{host} não é um IP, host ou link válido", + "duplicate_host": "{host} já está na lista" + }, + "panel": { + "empty": "Nenhum host configurado ainda", + "add_placeholder": "IP, host ou link", + "add_label_placeholder": "Descrição (opcional) — ex: Roteador, Servidor", + "invalid_format": "Inválido — informe um IP (0.0.0.0), um host ou um link", + "status_online": "Online", + "status_offline": "Offline", + "status_checking": "Checando…", + "tooltip_check_now": "Checar agora", + "tooltip_add": "Adicionar", + "tooltip_remove": "Remover", + "tooltip_confirm_remove": "Confirmar remoção", + "tooltip_cancel": "Cancelar", + "tooltip_drag": "Arraste para reordenar", + "tooltip_close_form": "Fechar", + "tooltip_add_host": "Adicionar host" + }, + "widget": { + "tooltip_all_up": "Todos os hosts monitorados estão respondendo", + "tooltip_down_prefix": "Fora do ar:", + "checking_now": "Checando agora…" + } +} diff --git a/link-ip-monitor/widget.luau b/link-ip-monitor/widget.luau new file mode 100644 index 0000000..9dc9fde --- /dev/null +++ b/link-ip-monitor/widget.luau @@ -0,0 +1,87 @@ +--!nonstrict +-- widget.luau +-- Bar widget: configurable icon (setting "glyph"); turns green when +-- everything responds, red with a count badge when something is down. +-- Click opens the panel with the full list. + +local downCount = 0 +local statuses = {} + +local COLOR_DOWN = "#e05252" +local COLOR_UP = "#2e7d32" + +local function downList() + local list = {} + for _, s in ipairs(statuses) do + if s.status == "down" then + local text = (s.label ~= nil and s.label ~= "") and (s.label .. " (" .. s.ip .. ")") or s.ip + table.insert(list, text) + end + end + return list +end + +local function render() + local children = {} + local glyphName = noctalia.getConfig("glyph") or "activity" + local hasHosts = #statuses > 0 + + if downCount > 0 then + table.insert(children, ui.row({ + fill = COLOR_DOWN, + radius = 8, + paddingH = 5, + paddingV = 1, + align = "center", + justify = "center", + }, { + ui.label({ text = tostring(downCount), fontSize = 10, fontWeight = "bold", color = "#ffffff" }), + })) + table.insert(children, ui.glyph({ name = glyphName, size = 14, color = COLOR_DOWN })) + elseif hasHosts then + -- everything responding: green icon, no badge + table.insert(children, ui.glyph({ name = glyphName, size = 14, color = COLOR_UP })) + else + -- no hosts configured yet: neutral color (neither green nor red) + table.insert(children, ui.glyph({ name = glyphName, size = 14 })) + end + + local container = barWidget.isVertical() and ui.column or ui.row + barWidget.render(container({ gap = 4, align = "center" }, children)) + + local down = downList() + if #down > 0 then + barWidget.setTooltip(noctalia.tr("widget.tooltip_down_prefix") .. "\n" .. table.concat(down, "\n")) + else + barWidget.setTooltip(noctalia.tr("widget.tooltip_all_up")) + end +end + +noctalia.state.watch("link_ip_monitor.down_count", function(value) + downCount = value or 0 + render() +end) + +noctalia.state.watch("link_ip_monitor.statuses", function(value) + statuses = (type(value) == "table") and value or {} + render() +end) + +render() + +function update() + noctalia.setUpdateInterval(5000) -- just keeps the widget "alive"; the real data comes from state +end + +function onConfigChanged() + render() -- pick up the new icon when the user changes it in the widget settings +end + +function onClick() + noctalia.togglePanel("nilsonlinux/link-ip-monitor:panel") +end + +function onRightClick() + noctalia.state.set("link_ip_monitor.cmd", { op = "refresh" }) + noctalia.notify(noctalia.tr("title"), noctalia.tr("widget.checking_now")) +end