From 5f6031e32dd7effb7fdaf30c0292342f6a832699 Mon Sep 17 00:00:00 2001 From: vados-dev Date: Sat, 27 Jun 2026 23:20:03 +0300 Subject: [PATCH] Backup for MikroNUC created successfully at Jun 27 23:20:03. --- .../20260627/20260627150002-Config.rsc | 3683 +++++++++++++ .../20260627/20260627152002-Config.rsc | 3684 +++++++++++++ .../20260627/20260627154002-Config.rsc | 3683 +++++++++++++ MikroMaster/tmp/Config.rsc | 0 .../20260627/20260627232001-Binary.backup | Bin 0 -> 362135 bytes MikroNUC/20260627/20260627232001-Config.rsc | 4861 +++++++++++++++++ .../20260627/20260627232001-Diff-Config.rsc | 44 + 7 files changed, 15955 insertions(+) create mode 100644 MikroMaster/20260627/20260627150002-Config.rsc create mode 100644 MikroMaster/20260627/20260627152002-Config.rsc create mode 100644 MikroMaster/20260627/20260627154002-Config.rsc create mode 100644 MikroMaster/tmp/Config.rsc create mode 100644 MikroNUC/20260627/20260627232001-Binary.backup create mode 100644 MikroNUC/20260627/20260627232001-Config.rsc create mode 100644 MikroNUC/history/20260627/20260627232001-Diff-Config.rsc diff --git a/MikroMaster/20260627/20260627150002-Config.rsc b/MikroMaster/20260627/20260627150002-Config.rsc new file mode 100644 index 0000000..d276389 --- /dev/null +++ b/MikroMaster/20260627/20260627150002-Config.rsc @@ -0,0 +1,3683 @@ +# 2026-06-27 15:00:06 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2442/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5260/20-Ceee/ac/DP(18dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra dns-servers=1.0.0.1,1.1.1.1 name=slon2.to verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/700/f14f095d\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:03 22.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set use-ip-firewall=yes +/ip firewall connection tracking +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set udp-timeout=10s +/ip neighbor discovery-settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=Bridge-LAN list=LAN +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 interface=WG network=10.8.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +/ip dhcp-server network +add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=\ + 10.30.30.81,10.30.30.33 domain=WORKGROUP gateway=10.30.30.81 netmask=24 \ + ntp-server=10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=8.8.4.4,8.8.8.8 verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc type=A +add address=10.30.30.33 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 disabled=yes name=mng.vados.ru type=A +add address=10.30.30.33 name=mgr.vados.ru type=A +add address=10.30.30.33 name=prt.vados.ru type=A +add address=10.30.30.33 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru type=A +add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +add address=10.30.30.30 name=MILLER-LEN type=A +add address=10.30.30.30 name=miller type=A +add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=149.112.112.112 comment="Cuad9-dns IPv4 2" disabled=yes name=\ + dns.quad9.net type=A +add address=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + type=A +add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +add address=10.30.30.10 name=MikroNUC type=A +add address=10.30.30.86 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes name=MikroMic type=A +add address=10.30.30.95 name=VADOS-NUC type=A +add address=10.30.30.98 name=VADOS-LEN type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +/ip firewall filter +add action=accept chain=input disabled=yes dst-port=18880 in-interface=\ + Bridge-LAN protocol=tcp src-address=10.30.30.0/24 +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=22,8291 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +/ip firewall mangle +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + disabled=yes new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-address=\ + 146.120.64.211 dst-port=443 fragment=no in-interface="ether1 - Unet" \ + protocol=tcp routing-mark=main to-addresses=10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system package update +set check-certificate=yes-without-crl +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no diff --git a/MikroMaster/20260627/20260627152002-Config.rsc b/MikroMaster/20260627/20260627152002-Config.rsc new file mode 100644 index 0000000..c6917c3 --- /dev/null +++ b/MikroMaster/20260627/20260627152002-Config.rsc @@ -0,0 +1,3684 @@ +# 2026-06-27 15:20:06 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2442/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5260/20-Ceee/ac/DP(18dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra dns-servers=1.0.0.1,1.1.1.1 name=slon2.to verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +#error exporting "/ip/ipsec/policy/group" (timeout) +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/700/f14f095d\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:03 22.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set use-ip-firewall=yes +/ip firewall connection tracking +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set udp-timeout=10s +/ip neighbor discovery-settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=Bridge-LAN list=LAN +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 interface=WG network=10.8.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +/ip dhcp-server network +add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=\ + 10.30.30.81,10.30.30.33 domain=WORKGROUP gateway=10.30.30.81 netmask=24 \ + ntp-server=10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=8.8.4.4,8.8.8.8 verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc type=A +add address=10.30.30.33 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 disabled=yes name=mng.vados.ru type=A +add address=10.30.30.33 name=mgr.vados.ru type=A +add address=10.30.30.33 name=prt.vados.ru type=A +add address=10.30.30.33 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru type=A +add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +add address=10.30.30.30 name=MILLER-LEN type=A +add address=10.30.30.30 name=miller type=A +add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=149.112.112.112 comment="Cuad9-dns IPv4 2" disabled=yes name=\ + dns.quad9.net type=A +add address=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + type=A +add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +add address=10.30.30.10 name=MikroNUC type=A +add address=10.30.30.86 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes name=MikroMic type=A +add address=10.30.30.95 name=VADOS-NUC type=A +add address=10.30.30.98 name=VADOS-LEN type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +/ip firewall filter +add action=accept chain=input disabled=yes dst-port=18880 in-interface=\ + Bridge-LAN protocol=tcp src-address=10.30.30.0/24 +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=22,8291 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +/ip firewall mangle +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + disabled=yes new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-address=\ + 146.120.64.211 dst-port=443 fragment=no in-interface="ether1 - Unet" \ + protocol=tcp routing-mark=main to-addresses=10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system package update +set check-certificate=yes-without-crl +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no diff --git a/MikroMaster/20260627/20260627154002-Config.rsc b/MikroMaster/20260627/20260627154002-Config.rsc new file mode 100644 index 0000000..6f4a47b --- /dev/null +++ b/MikroMaster/20260627/20260627154002-Config.rsc @@ -0,0 +1,3683 @@ +# 2026-06-27 15:40:06 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2442/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5260/20-Ceee/ac/DP(18dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=HP1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +add name=VADOS-LEN options=HostName +add name=VADOS-NUC options=HostName +add name=MikroNUC options=HostName +add name=master options=HostName +add name=MikroYellow options=HostName +add name="=\"Client ID\"" options=HostName +add name=iVados options=HostName +/ip dns forwarders +add dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra dns-servers=1.0.0.1,1.1.1.1 name=slon2.to verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=no +add dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=no +add dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/ppp profile +set *FFFFFFFE use-upnp=no +/routing bgp template +set default disabled=no output.network=bgp-networks +/routing table +add disabled=no fib name=To-VPN +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/700/f14f095d\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:03 22.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set use-ip-firewall=yes +/ip firewall connection tracking +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set udp-timeout=10s +/ip neighbor discovery-settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +# ipv6 neighbor configuration has changed, please restart the device in order to apply the new settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=Bridge-LAN list=LAN +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 interface=WG network=10.8.0.0 +/ip cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:2 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +/ip dhcp-server network +add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=\ + 10.30.30.81,10.30.30.33 domain=WORKGROUP gateway=10.30.30.81 netmask=24 \ + ntp-server=10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=8.8.4.4,8.8.8.8 verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc type=A +add address=10.30.30.33 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 disabled=yes name=mng.vados.ru type=A +add address=10.30.30.33 name=mgr.vados.ru type=A +add address=10.30.30.33 name=prt.vados.ru type=A +add address=10.30.30.33 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru type=A +add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +add address=10.30.30.30 name=MILLER-LEN type=A +add address=10.30.30.30 name=miller type=A +add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=149.112.112.112 comment="Cuad9-dns IPv4 2" disabled=yes name=\ + dns.quad9.net type=A +add address=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + type=A +add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +add address=10.30.30.10 name=MikroNUC type=A +add address=10.30.30.86 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes name=MikroMic type=A +add address=10.30.30.95 name=VADOS-NUC type=A +add address=10.30.30.98 name=VADOS-LEN type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test-IP +add address=geoip.co list=NoVdsina +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +/ip firewall filter +add action=accept chain=input disabled=yes dst-port=18880 in-interface=\ + Bridge-LAN protocol=tcp src-address=10.30.30.0/24 +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!Trusted-DNS +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=22,8291 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=!TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +/ip firewall mangle +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + disabled=yes new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-address=\ + 146.120.64.211 dst-port=443 fragment=no in-interface="ether1 - Unet" \ + protocol=tcp routing-mark=main to-addresses=10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + dst-port=80 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add check-gateway=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE port=18443 +set www address=10.30.30.0/24 port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system package update +set check-certificate=yes-without-crl +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no diff --git a/MikroMaster/tmp/Config.rsc b/MikroMaster/tmp/Config.rsc new file mode 100644 index 0000000..e69de29 diff --git a/MikroNUC/20260627/20260627232001-Binary.backup b/MikroNUC/20260627/20260627232001-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..818a07b33021264afd6a09ae566c35c1987bc2ec GIT binary patch literal 362135 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≧D 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%0Awvw?<@r)3Sz zNt-mp+=|n zw&*F9cFX&|s8s=CoWqhIX|QCBlL9GNd;iSUr$gXXAs+^}*k`o=Jawrcp<2g-cAj?= z(j+c_49rh zsKY!1ZHS0bJfjTR9|AjhIq(@@?b_syIG|TY=Hh0RhOz%uIXI1)8gK=-3(;XB<1lvA zL_Gt>JNW^Y%Zl(FL2^=|dttJi0}D|*C-LM9Sw?_we6D9B=j6E!zCPL09o*DBg$56O z@ajFSDJcH^LcsGKOs6$C7{E^*FqxS6TM=cqhL9TqjG)Vi8MlGjAfdk=%RgxWOm`Fo zj)wC?0G0<_d?BDwhy-Qt_UlkG%Wwv#Vmap|&+;Ytg&ftLn zKpoLL+uuzcR?)Uy+&|5k{cayKrbvvt;Ltn*p^mq>5WS~(8vM=ZuI4@N+psfQN)}O$ zee)qU;ZaeAl5A}x{Yqy#i!;=`B&6eXNrA{~K*eZ4r43MaJoPrLOH(mW@Cz6pdN>joJbysxbu1r~)^-CDlB;#6rflr-uA-9zi^V+xCWei;$a^A>WyA)W4D{hBw=1=VkHGa@Wg&Sr8> zNsT{3pIoB+*Ve_F!MMF|KHGoKN^9wE#d3}J#>XOnEBLvPqA-52hDq52qBwQG7v~3U z>nbgw%}p!g!`-E0vv4=;kGy9Kez5cZyg7~ zO1R;D*C#HKE5k;6Y+}leWJiFg1Z~BmWV%Mp3EEKx?;iAqQAb|^Hyk_#XL?hVM?wPV zX{?RzJPDcxLhg$Gmdx@_>tilGAl!f=yMw^$N}_Wg@IGkE)%fgnc)nQ_Bn8k)N@q3@S>#=_u1n<_#_z&uY&Qk?`4! zO&+Ox4PC6KBzeO9Z$-if?sd?7#=B>9Me#EF7@7EPl;=O&q|0{>Ok%9o$oDM(GOX$p zAFa?NLg<#r1+G^T7gMMT&0Cp1S9JtS0v{iBGZ|I@3^4mPywW-ddNfhe=bS zRI^!oNR~Yin6CKqlb6Ji10`OAj$DpB)%_!~6VE#o5WM61&qmlAiU7)aUFc3w*V;#c zha&?u<(If*__v%XVVuAFZbZIMH-RUg)q(RuRYxkz50!0DmYace0?%aOi@QggI9xOD-KQ7riuigTO)T4$SW zGY_)2p?vx}`eb`}rLYBmOykUbhP(0pahmoMrqZsjXEu@?0cpzPvJIsaCn%TQRrzDf z^1X*F-l2833s8}c1w*hM0h9~q-j(Md``{UM;-`L?CrQN~gHV006C zjw6I4)298JUEZg5X@}S75E7z@udg1r-s%cZYbsA~k_^dRZ?kUqZQ^dj2{6+k^`P}P z8n==Qi0-=&Q%zq@)AV(C&k}hol`eN}Lq>!R4`{bkQ~dU&zc&WJ&h&2I7QxtPZe$w} zuQmWOlI-1tU^5`LH(UQ?ZNdy-v_ntShss22^}@>1pT0Czv89US0w@3K+(-BOdzXbE zzz=evV}{RS#}9xlcryQgslQ|a^R{CEucgpM(lNfRK2QP@6 zvm>43$j#=|Kqi3!wBU*ySl=j#n1b59Jpk5dNW%@x~KtEks(iEcciSihVyxn6&9lLS0>Xg0O)Qsog>F&oFgK~IDe69F zP{eIp$6UDf(dRn9)~#N8Fo)@c?mIRQz$`On>=FpOONH)ub^QCoErAX$pz&fG-O$oD zl`~xVI0rg4yg$~deqQWr)aRBAHIBphvQ74=L{w^4Tcb_7blrgQLeIQ`+mXhIWwS{x z{4+BQx268^_`6XVpCy)Gc-H@1DqXcRtX3=iKyXWHT(FPIVq6p^}T+ONd@=!gOF=e~G0E5Ipi#2j^dgS%LBVF<}+7pAWZuBb` z6fwO;K%LCR;6Jz~gmJ^ITSQAsv>+nk!plEc`?OmMm|`fX(W5+$5o=ajd5udu{7=-# zE7$R*e{tyxsR&p$7%ldmxplfX{lF{-JvQd}&3CD@)i}f^Vr6h5AYI2t6hZtiIS<-` zh5}vw9iWo02hf_nu!VLY9ck%y0%>`&@H1k4(4b#TMY)oG$X|;?5YpDsKvC*1DS-dH z*}whQwJrZfB&&xCInA?`KtBrNFi#>NbCy05n2Z|3+m|GACjY5!KDg!35DX`!AxWQ? z2ho`KBcAfpg8SrOMbemyUxTkob&3YZ@Ia60tL=2g?AWyg>^}#ps9_a67vMYmf?oNM z-lS~P9q zqUEbBik?4mFFrP?jVRyL7F6GaCw5~wA(}2PpOSk%azV|y zAn-c15n6-%LZ;K;_W|$$#$VAZ(cX&!&{v@C$X>z@a9+?=1&`dBuT9Wt3d!J5Ugqjv z8Y-->5|SjoH~=gnfKyWaJS124*aqarxL1$2cVl-$KJWr!c{?T1K;vv#H^@Do{z3J> z)bV$R=ycUw2Mw1MWE?^NNL3v!=qN;9qj-EuB=`(VYF2$Ni?e@Ud(t8f#;xFimAD_n zlfJ?yI;Tn8-_$jKb?JF&VZlVBfEd{*PRYS=B#mZ*1W;H|G&wufp&1%?XU6szEzv?r4#*D)#nnFl=z@Wna3rv;Gy!>&K& zK2n*st-{EPsbqDcEJl?s%D?*0MQb7t8pNmE%Jx$>&<&zR_rRu>#A^|Yt`zEI$AXU` z66^Ntx&P*snH)I`kv@dQ*a%=FLNN%%1%_A!M~Jg7`#CNUH_Rk3&HN0B{rG#^aOVN* z?~>Jx8LCusQr_|ZR5AA-!qm1Zifa?nyPx&9hu9h5$;fwS65LsA?(NAe=>@~ST;hl5 zw9xhYpD%{T5_+GjOdW*lH3dIhrGBAjie;V43H{{llBL14PRK3R}cIS1_@A2oTa zHFaHgY&a*9bVRRYaJ5dVSBG7p6L00vRDcqzJ82K{467-jt=RkOVwRZ}7|oa&!Y!4V z%scFMMOufQ%94k6jjyIHq~)z1AmXtmx@^|DQtR98xM7QDDrKR#f>sf8}b?sTkb)*G6TomHZDA;`$7=r^o_C8qpM({`H9Wr+4JD%z{2=1f&= zl;0C{17B(}Yn?tq_KuPlJKkb#Al$-l(S!@Eh>y&^WiAi?US^pKsa;I>()b{<0h(|q z>^*4xm2(r0;Q*8p)X1&sJLTaGE^`0`0x7VD7+HyGAN|eEB)bQCo3m2q3=H}d({$#R zF{|8H5k2E;@@-j4FW7_E@cH0=!m)7(4CY84XDdhTc`S?+kVsQO!DKy?%gXOM;T3-Q5r*L zC_<1HkhaE`pgK#;ehmCBiUTg>o8;N*5U=l9L|*byDqKYwqe36c zPdOG$HsZHMc$<@857h-t$x-h=IL>JpET&>$^2`$!WV7m5fn>MfdGiJrmjS(oGQw<3XxVpjs51nm_`yXC5m|5CZoBEXkfy zQAnPLi+$l!y?^b;#-SWGWnvRDc8^cT*U$Kr`+Sy<6r9|4F52o1vOV-Ti}p;?J{Seg zG^Xjw_Y=&TJ6-3{0AYvWsbK2w9T*SqfK9F@w*^3^ER2&@JrIED@SOrUXo0g@yw0$V zk`e(S{k5O|M~z8g2CaBiAkISE#G{RL4N25>YNVSNo~h|74={B|mUCrq@;Ik1hHC|u z!9Hb;Q}xzDUp)XR(ESgx4Huv;41R=But&>LLk5IZX^_?8(-RqwF+4^l}xD!@0S?_sVUfXCJN+3nS!&} z6J$M87iR$_HhsL@uF>mhRP9my?qnurkc@p7y*MO*;O^#H1B&+PA#NEdO=K&sVI;8C33Ljk;2O8&RMLma!q4y5(Kky-cw z8t?&3#GSRcqK3*>#sC4E!F_c^ZZJFzy+2n_|3GINO3JJ`inIWp@b!->ef38;f+V`$-6iT4+_>p7T+q;JyO9U z4I|hH#Nl!E)T{ZI9`%`h3G%vtCowMT*!Q_tsoBwxx3_*bkQS()gZIMrfE^5uyy?0Q zy+hHx6}9Evg{gP>(Kukv7MVjN>nXHeSlJ%3$BuMzAht>LbHiQoqqMK!cu@xtc{jz| zIYOX#WSgfLZ8vakV8|y+gm-9_m`8I!h3%~RqoGf>JQaeX?S*>s?LY-8O^zmvoJJbq z4*xTUw#ZGgelD~iZfY-Ey=Yv^gLqhrszYswT^Tep12=rT{yZU17f+D$!*Qbx#$%ux9q<2kHAV{!c+vM%!6subJ^7Yp$=j7^PKW+#9L=}> zqLsWgglbAOIyP-g7vyo8hij{Ut`{g#r116i{L+JQ13*6)|KkOg=r<>^7R@NV)h84o z@;hTqtYn8^R9+FzSTN()xAuH13aCUAX5rASoYO7dr*VN!0t@eMXnM&jN&}HU0>m;G zn>g6-{jFL-VB!Nm_@VBKzf|0I6F_l7W}*g_m1=5@UFHFio^TqA2vh~9S0*2j`lP^C7X#yb}DkBR6 zFN0HF+eRZUDvn&t>v6;aY zH&Las>6^E29=<9U1rCjQIJfD(_Y5-}a^4Zg!Y3ov11v9$?B~=1UftJl$0k5^O3hes z=Yw60$@SPBSUF-`z2Le78u{~NZsW&FT=NrTWP^Cn#Gv4>Ge-o6aIMh|_2W zy#z!!^AM^NkPEIvp-?umDV(Q)h=IsOK}+30g@m#wd&EQ9}xdL#?BvcxMwR~VZfH&cjApB{u_mY5n8x7W0EGk02nuxjrdiX`wbv^Vj zPJ8>L8^fWJPP54Y`M*fsG$##Dc%8qaOLm9mKZzOzwfgBNnXdj7tI}QJBz#O~zkt4z z9D!NGSUam?BuIobf!0E4O{q%&5Gpgnq`aBnVTn@=(^KE^9Qa!Uv-xCkTowL1Rl^WR7ln0xEX+Xp%P%Y#uR8ts4WZIwY>x>y($x09*x_Ulig$?5#zwj|LTMnAD$ICc^ew>SF-f%9kxk4U<2|EwK6eWr zu61x%Aq+8tpZwTZ;0SX(SJGVr;q&NFs-<{fTd2iin8Y~H-kP#;(N!<&fwh=5`Qa-L z6mcE`C<^=2DNhfYaANc91ZovyH)?oLjGcEjZR}UWGjGaLm760rY15o<^NJa@nJOW1 z>c2Abn86%l`gA|6Vi^<{i?>_PG7#4vTJ@g&x1Y}&R9Z*vG=-Uk?)b{Rhy z&1`As-NsP3fcxWOimZHFv!@3_{tof!ZS927cA0#g5tS(mfhn}Tiex77e<+Ii@6)m! ziq>9eFOl;6`|EImZL%rI4`2ESJk$8@|8uqt<=Y~<-%b!Q20Dk-QDXM}^88qFU{j2= zafj{uLa5o}0z$adrf(tZE^ysBI-!Kr@U&WH@KV#@IBb2rpVnvei8tbOcD^9iJzigM=Gbg$A^+QVO{(0Q-B#7Ugg6dBJ6(#@@+spUD%d=tPMkR|fM7SFON`7aN^D?C@@N6ca3IkDUKH{$%Q^Naby?&lz*jMXT|^@?3v2&BMmvZq@y z%D8>c8D>HD!|njvAL9g=JGNBirBBMxTC|v~Pw2B+iZ1d7L3wDvA0nxuWDR&|18Qj~ zAEBr<8ci+cKG1kXi%ynE1~SFnihqw_)0TV(2?^*JMP2a?Y0YSd+N;N=&-lF0BX=zb=#ml24f>L8(ge%Fd8S1A+d*9gaK#8hN^uB68Y# zw`nm6QNK)for6kIXeY3d9@jyn7Scv%4NqAvcWBnF51zJu=cyrm({EZTQU!}U-;YM=K zL1fTF{Xv$JH=+)3RBmcuQTG#p^80=$MpumT zItO>@mwLuhaqDnn73jU5U#khm>tb#dN^eoE~h_ z)9B{l=d%fo{C(@oVa(&(dJ}G5fx951&xMc_~eTH~)15Q>w1Ir>6k~R-uzu=tON4IlFMx|#t znLzP+oOILT*cYFz6lY7u_5>)=*VEg=c2>;njnYM@rTzb|&XUdx$gl$*G1}R9)cH6q z?FQH@MMBwg+Zw1c_qp@~!&b&dZBY{73D8H3$snHWTrHC(ZxByX%>Kbh?FS_0N6kON z5an2>Q}3LX$A*uL3^0Xyh*WbG3rQlMW5nB+8m^PAbnM%>GHZipd~}f}q4&_vwQv+` zc7k}jq=$H~k&U|}I(<;4dk!Bdap2S@m&_9%x<@iTbO_4F{kH03t>7WIu#>OR+8Y4< zQCHrbvW)}#82A;5XyGGef_rS+p5kXSGKAwBT#hOjrwQd#wLg1;7l>Fg3e6O@x)-Q` z75v7!_h?`ISyYpv<2Aq+r|iY@Ew-eBnDN?``mfPSI9%qnRiIpd)2Mu}P~cjlrn2j* z0jXI*$e0%IYAV|1!1tL7)28*hs;5CMpOv+^5D`j6ncZKUHl=Yrq|S@YnU}v280y$g zwD!7Er_eVwUMm{=lbOClARc*nSlTMl%yC6@kL#?X>xptA9ENvXAlOJ0J9 zTg$BQx98X_^|nMD)5J4BYvWHcBRAa&>$qb5?}oClTU%<5c~ML20yKC(<{`4rqEmW` zvQP4`SYuZZm|#@?`;a}=S1i-$UFJiCRN|@0N_jCNz1HDy0rZO(uy4PU;(>^s;OV^t z)#XfO4>BZ0^hLj8^^Y8}X)m^-Cn#i8636{PR1D&Y)S!!x28t@mALE>~4n6r)xr>o; zhWkFzT?4npy)ZMFVmb3FK~vOM|HV}No5^)MDx>7z0AOW1PoYBq#Mj{ZBIM|`6G=;0 z1oUFrN-*U_N6{pY5^r@uG9`+fxuQ#b%W)kaOPQY&j2TlUHK6G90{RmH1 z*|b%z{+}fs_@oo0Bl^^*|C4n9_w5q2d=iXp!^1)H!PJ-zh2MyGi~s3nTY<$2*h*xV ziYj+H%5d+!!jwac^hg@23v35t8`lf{&uOGn!uo;T%*YBzAB9tvl2uG5rYXn-l={at zmmUtF(RLQTBaD0j`fwDkeia^hGk58HT9QuJOx z;$x{cHJ%f@s>?~8slch|LA~XIOC|bC4~?P<9s+Fjrm2vIdLUv{5<&KUb|EyK!tN2g zzDgLvxbT|SZy&B;Pg=|z`t)J-7px2Nb=gT8-`qu~m3zE3tVl0=7fj?4w~n3>;xAtb-Nac+>s38*Wb*(P=Oaau^&syzqL2}Z=^k#XJ#p<#x-_}5NhzeWYtPr>cPwYie@Az%@ybQQb!(?hv!iZN?Qt8 zb-WN0)$nki*-&zQG;!2Fh96{aC-0pw86haZ?C<^3Y26N6V5^kkJ6j?Gs2nmuiPNAT zOZ{uUPmnZFPhFty@`zm9Dop?S&we^GcBD>RSUlmW^a12~IkiY2fY-q57-(MC#o8+h z-INbSOhCQw8%$e?fZ40niX(Ga50VeC@B+UxDDN4?u@SXVZ${ud?Y1|80P*`Wa~LW$ z{PSs=qG6%uAsD&Rt!{VO8zBB*sp*@B?UH!?J|O$S%#jP%3i3)EXgoee%(f<0Nv_CR zW>0!4Rj#mVAX^u?Eg?Y}tJikCbM9%bL>jDLL8E?AfS+s|M|>e9*4&75cjtQ`d1y=V zkUJ3Z_exbPEY?+pl}LEu(8^{=3{1#hz@rbEdP7r}VTslketa0a>Ng@adQnVAvt|hM z@BvM>{ewj;UPJ zu6}ySGqC_2=mc*Gm*x`%F&CRk*88V%9$G8Mpc{EiL#!Rs8CLvG_W5RWv^zpes23kHCo^Q$myZ zg+G7MRW_pP@d%n)`Ud1!8g;vu*}qIS*=iZ;^HXW~LIv2$dzl5&CDLEJzuHWlVJMRg zLu@3{^pf|CeWm(!0E);BTVJaAs)7L$Ep+}aUBJ@6&XoxtmNjLSL2^Av{lheKC3m}# zw26Vr2mf~9iYUlTc!fUsWBzS!xSW2v>l-evIC>w)*EH<%o&w(OMMQeG24K%IQl7sH z7H|Dm?G7#C426nI{aqjgWZVfdt~^O-Q{>xU?nUFvB-w$|Y3a1a6&f?ZpQs@PKwk~u zYd^mJ^-_1KSRF;GZUIZUPE78yO{wfFe^Nub-BlfYx#Fm30*-M_I$Qah;dfKBfbtp| z(`&|(&QpLMJ|jv7c%W|e5}K6)n`m)@gZC_<^5lfk(JTKBEAD{m@n05^I6DQyPl$!f z2RyYTt5hKFG{EXTb6vuw{~b>0C)w|$@?oI6Bbp1C0R%Do_*)cP`GVAt*!ummodj-9 zMdW+AWzUY3E#)SfNuDRfrm6c6hH`2FZj`4JNIz#or@r>Xo$rl82CJ8vWNmj~mt+6u zj{Pw#BQxI`93aJmB-D|L(lDP`?oau`*ptbR!va+(_`3%3)C=E_XEn~mhYY^hFnQIf zV+vjY(0cp652>La^;u!W)^O;_bayz1n}u98Fd|vEjInp@IFbM&p+O^)T+>$Nwe=*~ z1_o5`4gjR_8s*3BX3G#Q=X8Lt2|4lfEZYkMVjl(mPAZtdeRA8*(> z5tmaH$zsYHCa+E0BXb#y7nCDgX+O3i5LOki@bXx_CJ}%XLzIV3$x~eLS0=*6u@6wC zb(|H0u!%&Dx7qnEBw0TJ_T=Vb(c+yo&eWj6>*~3q&R1x|){6XlxD!(uZwA+Ps-)!R z+N#e;BKj|r=djGUEu%C^hB%=G00n0tBRc)pr_x|;G>i$sh)om0AiH z>QD%5lY&rd+aN8> zhBO)n*UJx*!pIBt=+;3`ODzTSR|GShS!J>#=rR!SiL!PKU0nNmzq=oV=Bk))mj0S= z9ruf{463sI*a+Zr`fZe^YlLUB=J>bjz%K6-Qz#)wu$rBc;sVNc5*}JkgF3Pq$eY~# z&CYDj3CL@jv|3+%2ft8>c$kQ1xvpvm=Ttc&JA+f}(kL%Ey(qb*ksUI1PeaGRXu_Ux z_ZFMw)b4kYfMu3wKPZz#e=ggA?~0pj-QQDBb}H}ys36`db@ow>1ZUS!u$hF@d#{mC z%2%*7ONFg9AKgA8W~M8rMTL4YcF-B!8;+`E@w$CinP08;4Kj9l3T2)1pgo~HB(f>C zEoJ*)?1w`e5qIdhF;omoQ(aCMYuuMD61ZD1=kAUQ@~rFImEiFiyF|8&RwJr;4E*%^ zj(Zp_r2>yv15j?W+5TSW^fbrlHuTffgkZ??ozfb<%Glw`3c*Jd>}Ayy}T=6%A|&c2K)85Sy1&Y1G-Mq zYh-o$KXTP*_k#|J%D;L4NSe?aU;Yk!qf1wZnnRs;bf?JcZ^J_zMAQ0sdZ z9j@T6Pukkf9md!(TtFU*c+LE#;>SLuq}FDEVZH|1eT!*GzilbL>2%+e=&;DJ@=Zam z((r#&X8ti@MT5qT735!9#fgy!hZgJz|2O!MHCq&qi<*&Kgz|z_@5qm!01Jr>Q+ZB` zQkXyI!_(gXM_hNeyI^_gP)JCyx>6!bG9~LGbClUSy{85S=84sQb1e_g zEciRx`*@St&t>!WdQw-Z4hT{&3Bw36N@WJ*{z^g$^G!QBb_VN>$gM8zCe@Jx@ zp1hjwqyBmFU*o@x%Z+XZYn_uD!$igiaEsnH(Q&HE(s<0s39XeyT!=AxqhCTiLide{k2zK# zq~q!>#puI6I3{8_)bTl=ugKKxLTwODeA>) zsBdsBD-y6za4mFRa3fWHcGZ-sfTfB3yYbAyszh1^<{%}m7EQo?W3y(#;X!O1QJ`x! zbC^yoNx)Y!L6{Z>#2_t_cXLAt)OWR2*rWUSw-cDeg{l09_KD;^mLt8l4(MZ|en2g+ zQv4(%K&9@dghvBeVaG5_KKyq>C3IGw<$2>mt%ZbqG0qX@YTy-zk}rogc$d#I1U46# z1pDY7OEJR+al9FoVj^Ng9e?v%(&wM0?+Ah>AV4RJCT3!JEQTKf`={maZk5|!4VfMw zmj?7t?~V2z+63XoF3&3C{>kyDBwlN$PTZ0~CB>H36c<%LiU&O7*fG_*e{-;F&HT;R z?Lk3OcgMIB!@FW4)T`m@Z06eNN{1xSXPuv}xfE|&)=u_W;O^O`R>Y?}&)b7sL}@7! z*=nv;fVE4JV0p6xDY5jJCHJn%kuqPs(b&@F(sIBsiVKXw<@8m)8~c`gIUcB796BdG zP39#tY>GY2G@^7VO;x^6?YTuE34UQ{>CLy^S%a%C`7=jUsN;t}B52|}oA zn5ZcHjp(l3niL>N(F!_Nf1XA;&5P*Kz1H2I!Z(P85n?E%1;1d z+=NItztob{Pf_5|W<6nVA4|CUTXv-{7ht@=ytLPxL4w zU4){2IA|044zE_%f`#&_dh7E!{F4<%yer$R+l(i|-wQH8jt4_C?nU==nII*FZQOraOE5mSfI9cuh|n;QJvHP-hX*NEtqjJk2+T3>CdcY z2eneI75dfmbry$mvz~?M;W+h4HWNvsgvPFf#(69;m}nOK81=@Th&)4$LiOWAcjY4y z&6x^u6aY9@sw2&SOJpHP2TfMr=(2ijWYg9hq?TFrCZ6-HZG+}qxb_boU%v4PQOZ~} zaoimyMwk*ccOQ9^z$fW{hqjJ?=s;|d%%gKW@y%dV>M2&2Zu*U(+2C}Hm|fDYwPh7X zAh{WvZZkV39KW1Qj3xRJ9)K(k-$59?-}Ch7KwJ{=&+v>peR;nqfwkZ=KaEk8h((V^ zEDTWZR8?vIG~T;mmZ4WqM7YSfivJyEyWWnmJfQR6vfI4aEI7y<`u=0;9&g~G?xF1^ zJb-4|T;_(IGk(uOs#oVD1WrXHFv;==k0?w3+g4b5g1N*CoJXMqhFu()wn*0dFpA{h zS(}x+gsPu4$z*1RPuOfHU*xMtbpVj}%6DSU6Co>$6gXyA$$)MRG53r|hp!(Ek?@u7 zqy`^k-&IpWa+tn{z!UM2x&FVYi1X5vE7#-e@OQ7Mui|Vz}L3Dmg1br^4p7OI=0N zq1Kn~C|M_z!63g5QJhKKh)ECb5ri5OTzJJmU?FITZPj86*YoGnphd*bv)s?I@XQ&6 zL9EDQ=S+JiS@nQDYc=Yp(RThGl5Qvs=oxO7j~M!Oo=3JZiVWu^7z=nLulqg2D|o+W z(n6{+Wl2RE!HFjkiMi*ee)nk?Iw))*cfz9f*_hZAx-`&+A7C6yeW_?7C_XAD4qv3* z3PAc)GTXSIRRp|_dvhFW5W+JDBCyV+*s)YAMjG}H*BOEMV!qBb)#)jF%osL~`x6tK zm4a}D|5GywlU0Kie)UR0EQF6wmN#?tQgwG$ zxzeNLy`m1FZ1GPo910}M*X=|5+p0tE3+(=K=k`y371!Dtk;UYIK&$b;bDA}U@8-2X z=pM#%JQA{T&}qttM#AA^piiz+IO@JGF50vW4~x_jq+!y7yf1RM{l==coXywM|cD%Hv~xe z%SkG6vN^krv2`G?F|r_^h5#LW~Gb(ly#Yy~C+*4Y&c z)?b}@3=l8X-Kpz5^NbI=t0Ie7=mBgbH`Tz&BG7pg%5vf~)hc?PtLp<1mZ^8o9B@kM11 z2uyd~M}}6*cI1W;s*l9zF4S+_u;(URDTThf92)E$EJjkIb)(4~zqHp(Y;+8Rh)UmQ zSywECb`w1@@7alCTiC!ri*B|=zPsV(;AM3r%%u)rmg80vDXXlqv) zPU%7s(x2d6#Hgoy49bzt3nona+EUPLjIm>kepoUH$V16JeN?wXoBxmsFQplQt1|sU zP`&`SyJ3>rS`BjvV9BNIWS4}12v+b{D-1>IwK|Asj;vZ-C;h@}s+FU4X}PG1Db%ZE zaNPCn$L(SeXS9}XOLy0Pgs{DI2@UylncqHPBq%jdvKmyit&Fbh=a^5D@0C4H^kS%# z*jFgljt^l@RbQ5e1{oj_-4KLy&;PV#mrp0=>=)gu1pt9UJ9%|7D;0}87T%{B9W5Zm z=v2^by!wo6md*%u$zD-Ds)wT74g?Ju-@@oV4w4U)hVd5;%>T`V`I{A<%NILuiX$Ld z&40Yz9h!!;WBc(~m2$VX?+~snw#*=cPQeanY)QA0MikH$( zwRF4BwIdY{_#1=0#T7^gP1reT^Ws;JX9p10GyU99&z9JGKK zlXms7e%TwHPXx#X62`dhZ_Vm@STaTc%|8ZRP$W;5%(pb};=iRM(%!95EcjZ!DDA{Bz_k2qX#a?NRJauGdV=U?pCy*Q-5b|v#!EWF>m(`*x${mPtG>j%2q}S{h%k= z>`+)26FMtz_1w8WbYfR8v+3B39725ors5$VhlOmy+yk(+*F_K~-D%Mhn?jb;!=tpd zI`WMUE|@6ts7!j-AcTg@68M$;VjMntsbRw)hxz}@K>s^&+uxFD6)w~nc z0$u3^UjjYSgLlvp07&T3(*eUA2kF?;-O`wQ66H)izyvXOEB|yp&8C&PM`qcpm|l*t<(BkVU;-)yFvfa-ymO`?{1d;X-vI&T~$~fkx;Z@JFIKC zqw7uGS#6U~4(t}VPeP9vpoy~(1`)lH18ne1f|b5|0%6_q0Z zrVF{^YK3aveW)8!rXi|9c83GMBXIGchQP^zDGldGRRyA8V6(f9j8MP{O9qquNI`)w z)CFi?l{+s{8Zi^G!N$usTzF2hIyjde`p}^;wlWz)Jd&sfYoZ|!#hAeb*A~ck}F)>Ft zK;z22N1T~1;o~Y(3fb7f!X}yXZS2xBdA9rPGBll2`YtUdVDgJdlbP;OPdA{0l-}Ps z$w8O=Q_$?eJgyN>m($x4?jfQ_9f6SQQZD2^CwmI-$?jqyl3k$OOyYk(Pu;cK(FQ22 zO{NuMF*Vh$wY4L0XYaWkOAD!eZT12ohk?d?Sy z@D)@ctiW&}xZgG88K~{J1+ubPBEf{#!VHmDC`uSrMTZSAGbmy{ZU}(-UP&@sr(==T z$C}-8Y;h?mG=a-nd118+sv za=G2g(oM*ByrFcoA`P(l7~qf7yLjp-hfu->O-lUiky=|t7QsL_9Z`?&Y+7>Edts|B zoVJwf*AE#M2s!@Hhf)gUWyR9maNo#LM>0}h)}r5tpznETcZzfy!y&{8M3hF4#OCkh z4ZW#hp;<;#2khFH0S90{8R_wM-v2ZLKjAf1`m>)}_>E_F48U1aKLbpZgmQvtcJ4*HD z$DLK_a#%LC3W^lA$3+$v=mlm+sh&JJYv?69xN?ufAL%a4bk?doteykhsl6O$96wPz z5H^H2;r7bUtl{H#0RCu(9ha&2Uf1Sal3u~Nip~XM47MtXf^Myw&pm>9YVj0B2DM#5 z9B}ra@%#gCrp({mCHRQ(3lAi2>x3duhlaX`L~y+Wpv9^PHw{=3G{Hh~lcr!-rX0Y5 zTOz(C1xot{uw|dtpgoV^i~s>T?PWmDPInU7vNc0@DN-E#F)3B{FS1{fpEGxeFDq(6 zcC*h`JU+`~9b($*vqd@J=zHMMW-5f|y`QDg%279ZCowC~-d~{9D`dz?H`UXN`z+=H zK6Q?5?Vd93um*q>Q96wrdo^$R-D{UelNgrZ>pF?poSaey1HbIH`gbdLYI9rk?D=By z2WzQG;93U2r_6rykn;8o?X)q6{nG9_3Z&kEyCtkMa-sj|Y-X$G#;N8z zjkDiTJQyTBuVY}n5h@+d<0D|Z1VT^krL~ghG;&Wgv;g$bqt%sD>bcviZ>&y|5C;HM z8AP%lXoHCL5i&+4&kARhx8&Ox-+bG1ijy{3O7SJkJ$L3ZO0*_Nnbfj)+PT85BTIP{ z?3j57@kp&#y4S6iTVLZiAYVaYK2|fOophD3LhO9YmGB2g-81zNkh;iPe+cfM?vF;%D&dN@HHQ(T2X%)T3 zouG!CXP@6)641XIgj<*p4F0&lKHNe0My3IuT^?))ttEiA$KA``q=@nhbe{P4l9>a) zZ2z=susn&-3IIyl%kMMm9GCzn?2WrHzJm>w+Sry%dP<|Sf^UEEOG1WH{2}gqk9K`J z?-;4Bn%EYC=4h*;qTZS%zYte9k6J$D)FYA1?%f#8dJW>eaRwZO1ALK-A*|RC>$F+Y z`pSKiKot(9nyVU&$Ai*1eYw?T3hx3p6BIj`1r)q>!Y8F|>Cmb!+a&QH_}cUSeR^Ll zz$yFB6X}c5Pin7=Ru=2jvlerb%ZM90L&Y6JCul?h6-6D!>dzMagf_|uF7ui!UR5_W z2iSk|#QAIpW5Q9|=rE|mLNpGB(d4$v=5IJr5#^lk+ifYjWN+cZAe8LyQVn4)g=Li>(3Z$>RRFyV6 z;@YexdL-Q=8Ee{TMSFd0zEf|@W6QtRXI@YOyzzE|tf6U%--lP71*rS~S_-j2->C05 zQB0z3F)T4Ru;}Z~2*V?!@ydg{;RMJrfVu$rn1Ny|o7}fqRq&o?W`TQQ20jN-nHEiU zyF0z`PoSE}@TPJYZfs)!o!V6iXPlQlYC6XBLx-t>Il{-i!?8*?xz)$bXdU@sZX71T z3o}iR4{D%&TomWu_@pNBxh}`|E2++>+4ijD_@eD5$Pa!~s6V~sd29+loAw3{QLL#x zGZlgv8g*=fXXsT4$~?k_n@<@~yhapr^tgwB9frHVq0L^{wo%*DWo&L_C(mtX#}W48+- z=UPxJ_ayQysI{N7Cf6^qf_#n4#E)aa(Knf}63DXRKp@9&@Ir!W3SLjYmuN;-{;v2z z89(`19Go^65=VuJDBp3Hkdsa~;Ri+@$F+wTm7o89^*RC}f((5u^Kp4%y-Eicad#%a z>pZg;S&reoVh@8cMYa12!3e-7ec@0? zF(!3}Nz);gLG`i;R7z3xIsIvB^vcl7?jRKRK+h&MGQ&Hz_5b}3`XHbun~)tN+~0o& z*7X`5o?;BYiGR$AtI2=79VLdf{+0#ZNRySp#DV16_EQU$Hs-8Ecx-)WB|_2C-?BnGwn5zroeV{^$#ygafUHmHtH_vY z-%S?Yft!^nKF~-W%udx=q|3yb_Uq!KSrh^F=>%mUc)QS?l(a0VCG6f6c=Lc}k=^FO zeG+djHF}GZoPqP2`sRvdMo1_>&tsnN=-)-jZ-6;Rr(EA$v_}j?O`q$HJ<`_OTo_Pd zMXZl)Xex+;*@mo9F9!iw9C)%zIn_RZF9ext^Ms4VF8}Y!SduV6W&NV9cOr6I$udYA z(3RIAmAEx9US`djH?wlDah;+RYQ@2LnFPid*x$W?`z7bQF1IAJ4Sx8{U~b{HYs^yN zJMUYrBh<>LJ}(+mr$X$u175s zQ{Ph@n8i$VPPZL{dd55n0qE3GdOnV6t`Ej6SHtehO-?)4WfOVUO4Jf4IA!6c1JD2Xryp+( z1=9Io(@+kgX#Ud3zO_|B>D@2n#QOFQ)S_H2ElHB8KI&7UQv9xl5H2S1RHzcQ&dLFp zjvLWn#(;#Y&gr^u6H*yM*%|Y%b+)u;-flX@Q4%lC_E9<0#0{Bx+M2&LRJf07t(=G# zw(Fi0MmGY_zu~YkG$rc4T_GIy=RAT?Uv2!Fg5x7(_h@Sw*?=90HCLE_SwB&2sVxWl zVz`Cwo~tA8T1z5qh74-UnO88MZ!8Y*w%JwxrZq(%vgqyabr{_yYNplOwVi4%+GIDp zYRwiu!UbJeB|Saad3qr*?vF6muLec2xa2-2QFMamC9_q?fO^P$eVowvx5#@K|3#hEA0o!3pt!Bhf2_9Eu({M4(5haAsa$%P24| z`sm@Q8!j6SLH_wY?~;(F`i>aXmQRkwAzsGbPGReT&VL7#@7~Qx zekm*9m$Bgjy-7dp7#jtm9=)GSF@bcT>0256hWa0t3k9-S(6w42)Xp`2*~X+^S(nC3 z)8`Kdo%Q2OPnplrs|q0_!Q~z~bMC`eaI$PNZo0RYkcqG;tWZhK*;l;>>rtF}=w&K@ zJ?sr$oK0{f2+(BCH0Z#Vf%uXzy!0T1k7xK&?17JUK7}lHKt%?EA?YCi1*~V+v;DFB z>lQ~r-iP&0ZcQ6U*H^a1$VS@0AdZLf*OhkCO(d|fkTQHjDeJk?l>VaAWj|0F!ZY;_ z84fZ2LNCXCFT%bb>tSatev(yj6fcrbjwZWPaAzc*mV|896&Bsqlg6@G81$3L2 zu=mam;3iVe?E*N_3IKn;`&P16eb}pS0$cp@^DMB0R^=}ciXBkZR7|5~ zYrz*=Mts!BGwf9C>4uh6Sa?s?QMcJyX;-Ke1S~Bo zqwYv*f37Z7Q3kc%xCYi>d4xPhPp?#CF3j=OeL5uYAW+uKxzL;e5rHISOQr*Cv6`UN zfp}ETmJPub=T<#1D6{$HI1ZIAA7^`2$ZHA(zB(Durpxf2RDRRk%bZ_Pp9fw zb9)*?jd;-{r+u4lg9f(MPo0oAWdY$(fy&f1R^KiqnVmz$0k;A)*W%9d8IpZw1ckHw ztCrk!8iptsS}*CQgn(s(^yZJs14{<6H=o<{lnim=cmEw{uGut7jXftixlP;aTo%;7 zO_$9tMVSAh2=WpM%?3t!C7I{ZejNO#1Y=BqJy|@y+f08jrurMfysB|S>sd5$;>5|; zU$@8A&&*D)rjxcbJK6l^GJ3O&RsE8$%nYB!*_O7z>-HW;Cxk=gzHbZ!f#y5ijil8$0_fTXHtP?6! z5hW)6ncL%m6S8VUd!&tOL$}&BBY)=QWHg=eQF*4P4VJ0%EdaiEnm$O+B?zE+18-36 zL=ob+r#-(W+s=YhdnVd0R^}h{&7(36f5+BmZTQ+|c}1|w;W~)vlWTqWG&%Rx;JTxI_@Pj|e1@cH`#QPA>@b}#WJ0LCloIj#e>@{fK=A2#nH$vf z7PW}4Hc+^?nu1z+qMeeiy4jUtF4OB#vGDhki=TchANJDfe`FDE|a5W;=Af6;0y(WS{$aNZkRP=S=fr zj7VME#x^1)hja+c_8k+hH7K$b8mHLJZ8Y7M#FL_kArvWJu6xNu$_@zTXe#;R@M?74 zh^b{&K>%EI7wrgk*rA+@Bc^1$=XZQA(vH&Y**qvh)`ubuTBi^Qfjg^GV4-hF5z3{( z?HVZwCa`w;#gmEZ$L1Sv`!TYrfwZXAD6I9wr+sXnt2`cWNR{a*hG2KAlra-bN^a+W zZ1i?Xz+760VbjMTI#Rraz2 zPTNE}tX_lru_uP>r8;NL4)yRaW1RMS{7R+Ev6T)`0R};=nkiO%0_W#~3m?Z{4d*5r znrQ}`#Q<`jLK+XDofsS3D_>J&^%3?>9x%?$Bl!Li&{N%6 zObX&G!b}fd6DvM8eVBe&Eb&CGRunFcS{5kF#*1wukw_;pmXC~`a8eh13OKsHnxwO^ zFcPJFoz`5$vtJ~E8@USc)r7LDC#7g>@0Ii$b)MIv8Pz3B#fElcAyfta(5CI zWH9ANr4g}+Fa`5fAR-K6*qLZ6G1*PLHYL|KahEBchl?Ln_Kw>>clw(wAwSSdCy(s+$nr)lpDQ*jZ(tv$T=^eDzTj78`m3HT~=Fx6@j*%52oKKK7IyxA%y8nlOhTzA*8%Z&9 z3sVb8P$kP1|BoO^vMLsK!67$I-yKgLd&^C2lDabvG~vlJ12kU3Agm5H;#0|V{+B<;X!;+AY{3GO5y>TGAh9`9jUz5DPzETD+(mC@q*FR}76>Ag8mBxR+7d z1|a2LOIV8$?Hd@KN2brK;&|`)suFkZZrQ-U0(m0@`^-*{pYHfsa^dx!VEz$Xi#}*g zU$V8i8UC}%+NIIg84kRN^@U=+*x1ZI$}MX^L*FtviMDmzPvFr>s$6kzqIntcEH-ol z^ab&~m6VSWMu|CM;|Q2{3Uii)LIhv(j&b^$a$7z!wJCf}AXZX7G*HL1LT<0e`$S3- z$CD=H|Cbgo?`*g2tLK?nr36WDhx_ic!X8GiDWpMV+b6TR4%cQYljYaDeg6kj{VYEP z(megK{`e`JmQGBW`M~;1FlppaSXy!YSb_JylGRX`4ivS+r6^)OZphN}STkRp4}HGX zIS{ay4uMQAuCBzMa_Oh^1(+rssdf-3n*IckD~Oa)5J*se5JLI@E*mRI4g@E4Iu`8i z)(8WaH2;8{{8_&;(`t&?^?LX4fBo__O*3r)s#ZIP5;m^T!$)yc2G-|{>+vFf1PANL z;=V*gnV;y_WJhd^(NDO$&;9x&QE$-gokI6JO@)z!8yEJI^nwOq#qPdB)+gtA;J1kyHL&=J4pNokF!*8==Dh->CaKRlxv6z_K|)y3Z|8@<4<)b1;(6PGrvqpA$aBGr9ii-02e3W&t^of$rKsiuF}+ zhR!a=WQ2DOGe&jCza2KKZF?1`CnHn9UrH7|4)QY_ToFJgC_?>Uf)~Mu%miY-+XT`( zEvub9{UY!+=Rlk)RXE1NB_MMl5j?nd9Zu?l(!62-rLj;5|L!%ZEe}?BGpH@i&aMKs z&u}InHqGO_*5dl|6Fv{Kqxw#=Z%|dJO*Z*jPI*hO54Cr{@+Tl!&P>XqXuj2d5dF+5 zH4H&d6{$ZJg`g|YbSNHfw0hLc-^(7faYe%K3>#L3HI5?=Yd z_XAu7Zie#EhS#Y_XY?=9R>|PLB#FD^?2~$Jm|CG{S|j#YhZeQQlJBOiM1+DP)B_MB zO5^LpHD)An>sL0&=Oy9GwYd6T5nx?(?*-$NWq~ud2T~1a6YnJ9hMWWu$J(K&dvko0 zQxhDVR|vIijw(10XPkn40`V6kmMnQ*HX}X&s&)FnG$u-1i7C2r>6-jhCtz7Jx?RqH z_;ScgWe9C7!5|npn}KG*vr7M5yj!U%yZT(*O&Ja)5*dAqW8j|{q^q_K^~b)}X}0Hl zK;jJ9?Js2p2d+CK)Yi9a0!(s$h+`6lT-wJ>K!uJsaFiGet5Lbn(3_2gVpd;c7Z&PT zZ2TVHk`+GC(r+3Am9Wy9_<+wjm8@V2Th_rvnk45ZKwmS(X92F+A5(fnL)C_3IgumQ z`-u9igNP9S@MV@)j5Q%0*+~8B;u7tIG1~QjbTd`SZ24K&a=&eo7=(rmx+J#Ct}pF0 zM=XfZXap;ceDX&Zv*0?4?DH11A~3o}3v_l$CC^Ug|s3e%!FLFA&7045Ez{c!A{z>LyC_D zkZ$KHM1IJmrY)|sMp>cR+fK+ygW*p=xjky#@S|VKg|oHpFR1%Yv=VGoJ4HwM(jM51 zYCgPYs=F)Utkf}C%7i8=hGn3uogugcSBPIOL1r3g{n?RB@{}Z}KGTkTS_HOV8}R}& zm18oB4bJ^I?+&#$^>iEu6(;fv>VGHMjzD<9@9-Pga->($En^jDi!!ZKx8*R85-9YC z@KeIDgd^d;k3*zs>}uS7cbn&UT0ep+BkE*kfq%PmxW@e~Q9NfP%F3EkpMt#OWI2x~ z6TQ>$%#`5C^n{gizVDTt7F3=VkfVoIj9p?g2$X`ZbIVi*!J2AD*!vrz!P~nWEYir- zB`3F>q0L_q!MvDFnd{k&0q&AO5}zSrwZa5G^F)b=Q=a1S+`*fpL3>Dd=zaJuF!!EO zz=8v}%}?BHDW&m`d}9mknS`&5@f;05!H@A52OuG#shEq<)bmQt$9jEpMHR0sOiC!J>;{G!l`;8#`9N030iPC!W6Yz(9=ZIO+r= zzApYCB7v1Mkon#7PmfA%oHqG`5#{tN@Io%?wO!x&Y}wWhonAzu53J8TXmN$lj)mf< zhc(+hG4OU&lnUgZh(o%>w;lj6md5F7YHr3W<(CJSogC)aFi2^&YFd{8r^z%^I&Ok>E7R7}%x+dfjO7;< z^F~MsDvwq0hS)&c3J?J)_J3 zz(SNs#B%&&v=x{af@O)%Cgfn^;z=fI(L}Obl?*9a0#bk(Xe2Dbyp2siRNb5&vcC}1 zr_Cfxq6He?%_;GWML-PnqT(Se%>*vpH%^WkM`@*j###ii@m8YjdZvA$o;*T|$v4~~ z#%i^GQox{>;kPUd5BrG0IG(s0NVBh78hPc;Rc2>xI8=#5nr47d)J z!JC~+1|k5Px*DFSV5xLPXSmWeZ&{^_5;%Kdig&{JUFGA-GPWL5@Tf0N=F#bw$6{-b zLL<~2Y*zLFAjAOM*&(Iovr)@)Mb+>YSDPLrJ?$czBE9={7HK7Hc>MK)eE0B)u>vVXDT3yAtWCB-I& z+b|J~791v3N0tyRH3Q_d3KVSO*13;(6fEo7)EIW8`FcQc9g9R3?R?Ig^%wZtoQ&(D zMQmg$YgZBu#qw*=MLa?H;sVJ|4<6KGUrgtm`kf(XA)u^Abu^p;dpwDOQVQ^f#DZv7 zbk5@`>>h;d(XIBozX%>}mO^EH+cq75S->2uQ{5`O?l?z%$8<83bOy&%=`0)rH(FL1 ze4bF;q?VY^U%+n+%jGG1-zwslQTydRj&&Td$N(xBL~n?TAMyEb%pf$(|BH+^o`7^& z$wJuf`Gc?}FKZdB^#a~lh&7h=!^ezD>yvQc zxCoO+rqgEwbWJGs3$B>Y@uFON2>J-I)ZjXulZeBc_8778d-J2aBz^Y;jO{Hr6B2JV zQ!~>aKC^Ca;@zA)wL3^fJmMlGZeRa!3&R|&@!j_?7Eo?|8`DoaCw zQdc~3d;*DTkcqO@)P<%xqeWuy@bac)vD4h2x8}}yJh*Yw0ey7o;vk_hc+ozviu&K9 z4jv*Iu}(Mc5Ux7Iwz#w9HOEvDsgmP4dDP@ANm4Q&68iP;K%CxaFeJiSk!xfjaaKza zXS{z{J6qLBi~(QsokA{;w-`mKmWl3-E>F?~fTquJZ8nBsUq{68yw@m%_9PzZG?G9} zXO~%UtZRh`R;9L=FBT!2vGaK@0gWEexDP)H{Pc=>3Fzp};0NN-(QHx# z?r!J3y)D2$(T+}KM6EUD!npIzZ`jmqVwjvVu~(s(1uQbl#;5$09TOYEaNX{2Zf+?4 zd#S~!x~2%Sx&jWYHAIRuaPL#2`^I^5tsrx!v12s2%x5rz2R8bH zdNF_mXhwSj3tmWxkMEderIe1^r_t&M%~GmdPNiUBvyesBWv zCHzl|qlfX`@Ah7xSSXi2cY#Whs6fxUdj?bGfQo4T57Um5#W8#RPE|VzYf6DrHqQ3( zC4^GHGm#TKlM67@5&uirTpThxuad*%aU)z0cG8KwwkywSfE5-C!vh^!mXs}X4@x;A zHYRwVciWMy)$K}w^x@Y3przR{`;BMS-51f<={g7tp$mw>p9kk&oF;a2Pq3Fjf`aUt6!?1dP z;y!gFve(k`2_KSKjj13@$#WK$&TgwF#K#Yi4eQ&ty}pEmet2K!N=H!&Ur%TGT_rft zNs0^~yku@Q(r*tEUUpYH<-L!_%0?<Cb~QlLR{nZh)|+ zBtyYf0aKva#_uEV0fECF+7!jB4eeyjwl6E`o}_}Ip4%d29h=l8G;8R*`5quA_Cw>StSgoxl|oCjM;gc1*h@** zo|EIgR&=R5B>3uunnK;g#B=64LAqDNFhK|T-5(u>B|^N+YxAaf;l)z5^&oAx;QdAa zX63_9x)_fOhrb*+@CQ@DYC&+KXhVxL9sR_;Q)Xch9H9IX?Ey-h1bEzI9ej)cJc^o6 zmJz;k<-7!$XT*M$I?eMZ$Cvnedu+SnhT#^kvUhzJgc+M~?YwG&&mczy6$((8(~L9; z9p{9321hS1`%$?7Y2zOT6a%V$&gDGMhaf@SsnZa_L?*K-`WYpaLi-!dfC?Ajrb}6$ zvv!pk+BKA|nv^-LvjDxDQ(R*2VSZHe@off)3W)CUD^j(_RBS>-X`J3Kw}cjhp=UMO;)RsuXs;c{I7_5y zx1M1z3jWs-psyXlyTRm5t2-VQ#Cr|=uyJCtOTfxuw@iIa_PED_VtP~6E|2Wkv~|~S zwpR0lFq{G{8lDc*$KCXUh!1x%d-Vk;H}+H(2H13I;{)pGTBe`J`yCfUO(~hS%#TT7 z4HB23aR(i%h4irBo}TLs9P&^WPQ&d4pA+*}??j8~1pB||!ZVU(vms4@lY|;O&XTRq z-v&LH1=S2FC?{oc&w#F@>oe%VAiq&JG0vRbhK}mibb+kI_VAA+^bye9UJry2gBg+@ zHWkWRd}wj~j)cWpkfj@?_Vc_N3i9IYxHIRfDu`_Uh7{UMJeF+L%=g7EyRQZt`5-ebK4UopzL#risK7`yrPo^Fl)H*U`uN;Fz_YBFT+q2VUYb# z<-Dz}njev&LP*VFWq>xT!-^YMBRRi=>_C-KfQCDspSA1 zZKe^-q$l}~RAYdA^YcHVfsO($yUS6%o5@#+SB-q?jBoYmy;GK7W(}gK)cSN@fmfUXpZta!@%+iBg(}dsUzc4O;lzjA|?G`qWS0W7qBa zwrIwhxbl6MH)2)6_H;iJ56$?Zeobi39HGef4J*IV+A<%Qj-P&MhG4)ZN#d7j_yyiK zm(OAb8$K+%i?UH4#&{2)!!n}`jGrmyZjcK&_)8f-!;xs{tdgPJsZ;hCL(F2)BbtMb zf^J=mEK_IVG<@L*84c)+eFwSz-HIyOsAGl^F(SOwsvQ|zI(1=2tuTpl-L;_<5Brdk zM*L^p3G%vcZr%UqjL~h3Uj}_hQSaO$b@YQ}&WV~~+P&|uPe>WbdW@tom&3hEnN4~9 zDFpa={u4rX4)im7hH`pmPp-0{VD< ze0boeaHrRllAMnx84U-O4zth{CeP3t9%Mb0?fM06KdRYIy?)qmn!Qg zIW8J1#(@PD2QX;bwkGUKamu`TG!*XdEY#3qN3f^m8c_~&avw0T=_<6S2-Bml$E=vN zuNcOzw?6pUCk#F|LH6F`mIZU)cf|p6_-#4_9TqnRQo06n^=k(W*eyF=zgi9>Y`{;0 zwM(HED$D?$E4Tc%$cOnlK3zj4r{uxro2Ckqmw0Pzto$O&+d!G*d7HQ}@KXACEej_i zqzIM^8D>e0Dj@5#-!dD!wwzqu6^F|MWu*;T$d7yzAHcxH?cb|YMc(U&~Nw~L-BE>RR_ z3bs8SIf4Ks7Z?!M0TODPv4vtzwHlv*VvL6$M3*8SoXhD-yC-{ss+-XRC9*qic6~S` z6aFNvB>zhgzc_fEwIq9m8W}US!bpR0$k)ITnpRWR6BHvWxprph7sNEp@pBdqO&K7j zGn33XVeo>#Frji01H-KYo`N( zu(t1Hw3IJ{*2SY`xXAP+*P@xFE|8!tw2(K+)>NWgY|(G*-i$}A=M0J1hWuY373Afd ztf6&@QD?_#9P<=I)3<7IZAVAEhfDm0%p_y#2gSLqCHLll`T_>MAQA& z^L@~3c0XkULnGqKnN;~=61qz=$0|S#klOIX>A5C6s@1+Ev2q%6c3SYty2X?C#}_oi zrgydQ8*UN4)9X+?VSb!+6}CwGZddOH6gIzIQwRUWss%V+)_)rbl{thvGiybz$)^GyCn`nE){7Wd<)){m5ajnP*6!V_dX&nxXv(b#^yLbOxGo!-3x1WA>_mb!0UD zQt&h{Jyd2kXE7I!(W9Qg^_>%~(Ff&9*;Xrnfl>Lo&k}7a|4IrHhM*$%g^;d!vKF|; zuN%Bo-goB5Vv{*PKbaWBK5)Fdx!!;!aNX~T8YR|-1W2IN`b@xr&K2L($1X5&&nm*x zR+LJD_;OCR80ZqkMtnN3b^PnjG{N2OMqw13W zl902;m;$&g0o**W5e#}CZPJpU7$<6{c&bW`_1OS^bSW2s)Q4eHo$h;ju+M>6?&2db z8aP90hO`&jkUp(e#V4)Sn*9=-jR`Rc() z7~w5*$d=w1zFBO^c-4NQY=I*068Trl5AKXfZ;D=a#hb)U?}^h&I-1$TSnyBD7Et0O zbrP-gH36xNanV^(h~n%fp->+~NDTN2WK>`+{GpB)?JrH4dnu{I;rLplUT+#lBd;Ux z?|>+K3@@*)a>OgIL7skPyntNWso>B%;!zRPnWQf!5V8QO)S$IDiUQ=*P#G>p&7g)c zC`MU^VI8K>Hx(>XYT_Z`6P>3zQJuVX4nmz3^zx*<0{}9j&V89ah6wER86rEJsPu_V z7O}1v=nBPX7y#*?0AV&ILy!=W4rO&iJ%I}l1)p?63}gTTkCQ>ECq|@_^^l~eWE3rb zFXd}62Re143TIhT$Wi8NX#`}~rkZ7%^(|hRW!wZ_>vm%e>=pyc5Zgq|hQ1`TQgwTj ztC;b1n$-RJ4&9Q#9|}$i3vVZ*T+(U}VnhueIDaznvG>k?yFR-?TQB|?CQBUc5@jOU zvw6Yv?Ccs|$->x3Mdwa4vK-8?7Gv*@cbi>ur&o;b1%FbTkWCA-h<7h=(%ME>C79J?j}sCLU5%BRXh}*^lPyMgl-6gm+gtC|21f;#gUM-D6i}m`jF>3VgV*u3xbW? z^NDIX=(}z{>{^6cP}OYBZK&A#ZI5wl;+y20!Y$Uaqt6Fa&2oh&MfJO>q?-1FjUP7F zUsHD2cYx*eAE;#v9b3517E1DmqBFi^60Qk#VH2KG&ZlNYq3{a0*fv84FAku2Oa`N| z*^&|LGg%*g2P$(nzlk3dif7pbsM&aL=~;_?w z{{iqNMf<=emlRMofy%{tET6MGr$;!A#e4&(^XFv~=(?m`sGMdmetPS2_Lyt8&{a^1b@f(bY;5KZAX zp}xML36{m0a-drBXPn4vVe{xRIOH475sc}a>mXO|oHx?leT=3`UsMJ2Ec%7xFR-!7 z=Q?6cJ_-_SBnGBlO>HOZ#@L-u*@xu?J4P{DRz#%aRCPNeYQbwmemQiCTNgK_Bhtsw zQ;oU~g$TJx{}dG^-4J}!(W1G_Xxuzcs}9o*rgLtHBDQMfbkTw>wj$dFNOZ~FxS7>J z3!Pk*Y;7bPAsLeVC*o2s^Iz6OLa9TX($97)!cR#H7f^Q0*v)fue`V+01Je@r&aOBr z&SXbEeXhUP{#|x;tiRjcCM0jVwE+J=0KnYQ${n$R`Tw(cMQ;`nq?MHU5Y>HblUy9% z8zQcsEr=qLBxgboLI_2t)=AFc=G%~me7g1FhnE`DJBu;434Mdevpvc!xVMYqjODui ziYw`Mt*Vs~9AZ8lFzoILBo+#`w%%I+)iGXGZWw#mRr^7TU+sPEz}yN*tF7Nrb;f#k-Bux2P`mo^Tg;PXXOdnrYS%> zqkg0&^P2dVqLt?@0#c-}SOVj1HnpS_Ht&HY#~n--styR$ak-&zYMWnZlz@|YQ0adFj2oIqE{{^PvcDp4DC}OH&m#-0qA{AP6UiZ87N)~m zJvl2?z!C+c2K0>52u6Ld2S=Scf1uz_ko#d-Q5}h;9^W@6ik7khot#d)rD7%0T{>aP zwIILKX?^jMLBLs;dUSp5@)Vr2?`5zd2LXL$ZvnPD>;_syT1i^!{w1SV#npa0teUX) z^&l1b*3Iaq(5xc>&L-CzkUySn9`CJ5%}MaPZzjN!K5`=X$Kb@7G0()1jOHp-yfPU^ z8Aqx(G}5H*zQ`^TdU24l_fw2>o~#?k1S@ln*0|OD|G5!`kXC;~vtiSM_(WH+#DY%e zSlo?asQ?Hgbtg5CHNj{i{!lw@Y)O?cHG9QjxfAi72_2s5vP09H|E7oCUaah_#2Ld} z5}U0dGveurqrT#br1tqA_E%(tk5RZg@2cv#q(W90Zr}i|de~DbsGG{bUYY-iR&Tsz zU|JiXOYfUa7^h4l>}c2IX9D7X55mECeYD?f+sp{DQf9>GCi}MciYx@;J87#0^PoxlH#cLts99Eo zC(jC<4w+-6AdEO1uCEMQ#Rai%87QFL%>RiSC^KY_Mk`E67-_Z+&b*}lrn4p&63^J| z!N>F4-w;v(x*iD2foP%VGrd5FNrGeK%PMMS2pB&Y-aWA9K5Qtw(ZOWPhCVr*und?< z+066?W>a#ot*kjw$Mk=5$L6dJ_jsi{Z{!MNC;{Hj6` zwOlRZheGVuXZc{n%6pB@X|^iUp9y_^2vAgGU^ab+Afas038zcJTP+izK+Ix6SOtZ! zrba5~$Fkwec9d$|j*T>S_Ky2AF^o|Qr*R2^rF_niFC zrC9Ulr47JsbzyZq>w@Evmw1Dh6eaFpMWIz{f@TVx$FCqqPij(f@G(kt3}T4pj7k(h zl9{bLGq=Dq*EP=;btJyv2cI|J3>Sc%`H*Bvq~>WQEZFu(E(G5H~|7+7AL`Tpz9CKVDT=J^;&gMzFNo2%D;W=ic3+xu6+}Qnk{>x$9As_yE0c2n(Srm_eP(4 zn#y@j{gc*0HVJ`rPWhbeuQf#4gVsDx^xrtf2SRR~MfP-sKHwxdKjI0dgY!oHRYuP; zc(X??WM|SHpA1xliO61=d*2hFk`k6CW#37J5x=OqvD#C->S2rpz-_dgrASI$Vu0gR zqj8i#s}z_sI{5-s0#7x&FWu6Z1aGC^%o3JkI3-v6;OzdX@=e79!;1n z1}Lql^6&;q7@49|sL5K#{9^oop7P9C6P!QL0e8NYk+!fd=N8x`H=HL+gl$f3^6H04VP{A`n$=0 znTNEZ`Vn_OlS?}Y&t$_UAW(-U&7Jy>eEOhjc<01vKn2e?QKpL_;b7li4kiz~g#0gtb!ELs4Mamw$gZa@v%_Hk#ouM2<^_cg7& z#~>?I7IimJS-++{511FS&I9N+YrQBi>$eSGCT`yx=4#tRN^;(k0jk3 zF4^kw^BjBq+pgq(DK!GlD&8AN#&PM%n692kbs!j(! zHM;`Va7W|Zz@ZpBR+-Wu8*I4yqbIwP#E071BM?h}_LAjI4*G|9^mLw+O*If@3XObJ zWkl#ivKRY$Ex=%}i0S^^R{Gp)!AH(nTctR}7+Ka|s>&|8D90Mfk z=YK%Z^wEU(jHbdxu|<7pF#TdXw+2GwFXq7ITx$BFLeSwtv@gunlzbV;zA8R|Y3XE!q{AcGmYU+Z_4ES0o10>9e6CO+AOQZBJ@Eu zbuw3NUv=IIN95~CnsU#=t>+b0V>E#d8oyrX?!(yi(a$PeH*b)vWV4+G&EuERypPU- z+mJQH1`0i`bvU}zs1ZD@0EK*hTJbI1Cz?~G9l>yQkvyPxt}mGsBz7AiK~VrOsrCZX zrl0s-ClSv*I&~Fhqq6(S;_7Gs@f03gP$00a81(KW;;q>Ymp@3;D$c9XWpz@QW1yFb zJ3o}50L#RU*fOykA9IX}+qvl5>bdS^zww*TlC#PsKx*EzNJ%fDlb~%?Rpc`|G%fX2 zx)0J$yT!|6B<-bP=Um)y7LYi#!CJv9z0FKGJ5xmv&r$D1VKQ^Nr!Kp<vm8Oar zg^FFl?>Kw2j|`X4@5C|musi`Dnv+|R;F#uxb(_IfwY8$@{km9{s>=ej7~R-x>xyRH z(XNSIv0+=#U7XiwjzPI-lLO}ApM~#gwcrx6kjacRwnbiX9}sxx_7M-eY>?UW9gUpS zG_`L_#G>^LoB9Ae*iuZmk(`b0iyVWIh4<0lofgb1|!#N0nYyN_6;6pKrXBF&hggumW)qc z#N|QyPx{5hAFyc@U28itjGGAakC`?Y%5omaxvw;tgvMh$dppy#vowYy-`Ga zoxr>Gc7Hr8NEcYH^fTFZd!nhuk8mb|_Ir-PCs8$H?aZb*#}&qQEG3aVgzjpmAcg~^ z8W|VN{xH=?G{N}rR6O0@g<(rO;>1~y-Fi1%@8d==jth0-6;+1~a*?FWFlUH|Mm_`P z{KY0ki~d>Ab*DW*W-{%DM^%xxoCk!s*gQve&Rd!WCV^YDuFJ5nbOex8d{I+|?=a*)0jFEI9)lq8K9V#t`#!ASv=$ERNApggTS+ zj7ZMyi_y&itI`_6%S}WY>Bbr8(Xm*=_(Ou<(6Qd!;|1Pg+&I^q4e<0*uZUm27VeS) zU2Ft@&mI62`_|`KL~vrdlbCYi(9?IDaMwr|emofJ@`ItBp)h2a3}r=n6^(NR%m$ld zvjhcOydAnSKbWXqKN5*uH;a<8Qmf;mibYqGzzhy=bqES}>(IEaCLefO3k}Xw2$Jp= zJL=;m@%j>9!8nlowJ%}lKPPzZq#*syBu{j+_s~)R*`L#)+sim>@`=7#CQ{Qw+=kyL z0=sB%t2w-F`#c`9LW;zws#!MKFU3<3KJQy{C)1((IRbn)QqVg8nen3nA`TEI@TmOT zejk5_zX?k4@o*U-?u96P5?mv0KQ(f^Ne*6$)K~zMVu$zP6#pwwpl&AF%fNQt42!WK zB(_l1Z8v5k7hH`D)Em1^nSkhwxIfLK&P8?rp;O2_#Wa_vC`oeeBZ3tRL&gzK(d(rk z3i=`Dbi!SCxj3cY3=+8rpQdDp8@y^p;~z8kviT_ew3^+xLPg(tV5Ci{fQt6)2RpobUpWTJ z2tVP@#A+?z1lA(=g521iCIvV)W|YU>T3sLrevJVG2DV8wz>fYF9Rl=orJ@-o_Up05 zQw5x9c%FB3dh?JV<}Qnc48|`{1%FDx7PJ)erZvvu+@1x&+uRhsGaRc(s&hL zSfeUOGlhw2Aog7HnrDGQ?;tmO)D>&Qq@kax0>-P|ac*dlx{eW`7I;mPtj@Z36v)tR zi*VJyCa^P|#LfB?QC>vV-iBr!GJ4!mu}UrneX9u>8TjV^Fol$29|&Aa*Xqd9N2%D1 zhr;nIfVOk{A3$B|GA+&9;HHYLk{@s9d;iwlUm4G9*3@+lp~~oug;rP~yRTPx$efmr4mWZ=AVpnrzSh8_|`A!ms96UcJiP~rkFms{Nbv>q)6s)1J zG2(*Fffu@!L^K=hi+dC5_7jcxS$HTY<1enUZ-J;<1q~hRdnsSbCx)J$+!vZxfFb7_ z#w_ZE16L$;mu{KSE9+QE`0omb`F%=!6OYdnJe~)Hbdh*L8i=>k;VPNt~(Qnywg<-8qi=mFcr=np@TNfUT7 z#7L?>?#74gOoa-iGv4|yZnti>6pM<7|0QC*qg<6^V`rphdf%@#Qsz*uK3!)DX#vc}Ji&8RFsKVV2MDO?J)oaLCj>bNlScZpT<0m#%Q!e)U3vsYg(?(98 zarou$-9N&B`bBv6G%gN!`c*n0lcq@yg9E^CUcYY$vf=yEsUzOQEWLwTmBk# zl*wS-WrTUR&Bn?3gkIUh(630klVdI(h0zxpz0_U1(wK6r#i1oMrg9*4ra5**_|-iX zz=f723`;f!QP=er6^#hq@Xn+fcoZs)uv_P_dZ@?;We@S^Pb0FS8(;{e36H6zsk=+i}qO^FPIP zLD2ON+a|TunFu6{)=8mGw@%mejm-&~yMvJ}ft?b7a3!k99n0?u&RmN5p*26(vGh^p zi?&!xRqJ4u0|Kgce@rQn-1NIO_9uqOo=6jiDs{qZGJvE8mgZ_nAAvOzEn`V3)_I7J zuhd^mns=>MQ!thUc}6{D=aY9P*GzE5<&Gl zT{_f1O}~i{*ZBPO)^5gQYU}agxtX{=G`IK(&BA4XchIKL`PTA|4}Z~ZtZsLB*i@D8 z13%`3$W&JZ@rhNEq#PP$MmL@xghPkimu0oNq6S0N554{Mar0Gig(G|fZ6BlSZ)#9H zN@%-Yuj(^kEbac2GKvvj#EX5vd8*LvXkL|*&WbJd04|oOo95%ByBL(OC4;$U{HzbC zDi^_<$ywbm(X}f>BxCdlj>UYz%0@BH(wNshS<9LpIi4k zfqV@{@^AK+b;=@@WsXy_$z6RXbkOjs6at#AS&kE?nj^Epre)^K_eXLk)^6Q4CX;{GoY;0`(XcHm;FeR}I(_gDc^qw`XOfK~eB1sRXf5{VjmjGw`SQYZ?Wv z!E#c~&^piAAs_WRO zYtYt@W0(f?Imvpe#g>Rtq%?Sk2G$lW!WZ1~j?t)O#|a9%=~9@Xd*jNy?NV<7O{JdQ z3d~a7ogd3C3=U_TcdZc6=zCx4VIyAuBk3A49%iE%s&owyIiE^XB9z98co?<&B-2kOjRYlAqO?SQJBI>VZCs^VcF0iT1 zuf>Q1ZWhg7TQSp|{HU+}tuc9vrO}YmgM1KihPuq-F?ynt)P!j=(hWA{ht?-6H^F$f zmoaU5vPWGjPccSZJ*C^^68!;AG-}O>vu8{z0;53T2FC`#9ua_~3VVOX`upV&F@Qre z?Iu46YBpfN>G!jNO-C!AH&PdgfS^J%FF}D8d z&kvC5cCQ7j)nS-LBB@bK8=uI5Drx%1P(D@rd~@)kQTHbS-u%RTo$({u8v?HhlYGl3 zV4U`{vEDL_Ij~-8&A!8YN<3R>=b8q~Jc7fL3IAG*S;1fT9Yh9aXb9@64;=i9d#GnN zifICX;?icEco4v(ll8!9UD7Ma5UmF_tS(5THEG<3Rk~ISa!44L2(obf!!)J`P#UJ^ zeHV7;a8R-H?Sp@PkC{xq(5Bl!Q%lS&b4TS>$g}wOL$z+!=pfzE4Nn=@O5qI!sXmHi!?71X z+-7o3QC@}XRuN%pM-R0Z&5S=Yo+*RdC9JeY8PDh@p+Dq%62h17npA{P&I=~;7I-J_ zwTyQm!gl-L@Nb~0zSOz_yhhnrEO~@T3rK%e&0n8-{v!7xa+Czg1s72iWBXxq2h;T$ zl4sRvr=g~I;z48|=(mk4&x5nH@(bhS{Ehj`e_SJd>ww_8S4i>N!-Wz|=zWqdH@Q?cnZMG*Jw)k&`V<3t z#QVOYqt(?%J3;n2idFE$Z`}uDHOiJ*f@OefQh1(+$glGHmS{@L7^w7&=4NH@ZD-K~ zz}e2o$r&Gmzq0uZbSovduOl(Bw;c10z`9|#dGYR!%8Zy4w@hM#}v}N6n3TFQlUZ^ARrL>l?aNi3;R#NXk@+>o1TefJ2j-I;iv;1m0i3-LzmqaCYuH|eAS#TLd-}Gn^o^DTe|L@r(CdYCkOcN5;0G36h1-3u2xL?-$$yKg!N9U0 zZ_n%ptA@e}CjCS(_JvrdRA%e6&?R@s504S}q+G6Xkr4j`c`iWjq{#J6psMJH-F&m~VC(*2=Q^*w@uv8ccQFaG{*ZBXb zk&u7x5|+{|;~|2zS?Z`R8E*MSM!3b@28aID9q1KjHye zjRD)|;B1@29}rPI3aznXfWS<-oOdF(+V79O2s=3SFTRw5N=xUUJ8t59HwJ1jF@qCiv*Q?fvBCJ*TvDoSKK(V2ta&1r zvjDH%uP&y!diLompFo`h7u7Csp-WryP*@pg_05JnbO9nHhqDeSNbx?AFu<={nV5HJ z+`Yi66QKyK-qoaDI1MYXr662M3{~%u^pNXPYj5U)9e9rccj~xY>KJjKm>(d~Ec@5L zlP?u=Gdo%!9K9PJdg+dopKkzll%n5fjm@i|6bxAVAdTnaw3KinE&ZC1WnGnX`11XI z+4s~=Da@G=xi~5Tg2{dfBV@o=Q_T7(k`s#WXPv46XX18mGa)}E0i+E^(cm05`6#t# zjb)_OlPnt9Wy#j5R7txue5=XFLFBi)(pf2{^Nb+>@RE*ShC>Xx_|q33D;We>hB`Dy!tQ>GPz^8}kbzFCa3@1a73lvc3f4)K%7>S17lH(Og@qMF zvo&>jXaee{;`PIzS?mf63Qau935DzUM?MGjdjy)6or1yqumr1I4KK+NNtX!o_9^}` zhYBC~rUtu=+oqB4i68yjTGt~j2FUuk6{(4IC-^#bZml5r6`9Cu z5v8aHJRRd!JhlL}N+)ud=r-y?zT}$TDl&3UHyi`4SBHCedp_NqlinInUE1?z+bSfh z%e(iOi->mw1O5|&S=KWkoEbBvOZG7!%hVbGz!_3Ot|dakpu(&?C{eTaogn$Th2h$&&@D6LYT5OgB#)_K97@`HkTt}SBpVV2_0 zQ-hcqn)HX!yTAaW?)2CPOb>dA&TdLewF^ zh>DGW4BX`;KHx2qW!0votx= z+$fT`(0KOcs@{nl4i{@c%~=lG@5Q4eAz)Az*0ojSL_FEej|tqMgaVz#Uo`tq#&1j6 zLGe}LdLDglS|pf*#(|4j7S^t_SAcr%FIcszm!M|F?exQq$}u~rM;8k{%VX=nZ#osa zZbrccoe4xUxW1f8&0wm`HJ*dC^EkRrKRvWBWxzM;FB>0lO;8?yE!nH% zS1zI%tDAPr^N^A^HUA(K7VlQ+&Vq)H230o4J7%r;WDaj>pd6_yEU8FK)Rel(pNF;O zCWkQ|JHi28{(|fTuU_(GUO`kYvvwUrA|~*2)W8{4S3D)T|Hyftrn%UO!rkzWL`SyP zFX{^LLu|H@1>eCDPgGAAX+fv`x)ogZQ_0APJ=a_q47E~j&Q0P6^kxO(%Eu05D6Hy0?{f8X=OHT82O}fl8e$Q z<5A7PDtFkj=lbcx6u7pSv{a>>+xDP*)q;U?4sB4lo{ko+Po02LS1^ zO%{YU$Dv_r9;I5;l?Bd5K^RPTUVP)eAYt}9^9J!RR1gxGv^O?Vgfn>ImSAivi#`$$ zWFXCE!moFuj1AK8teKKj`Bzh(m1iMCD+J?=ap9;$RVBC?=W$Q?n{_D4&=2fmRAmPE z`>-6B4If1{)|Cn}o0|;|3E-7P7&k*5Ofhl*W5!{+1PCAf`i9Lk-or8MKvP?CGElJ_ z$+<@SeMsx9I!@LS-~Rc6J>^{%;chBL&<708XYqX-EKMF&OS(p^sNC8&9+y8?b_tPO zL-3V=8c6V`7%StyA#Q5<=Z6@|;Dc&$xIjwQvC-&@`Y2?IGCvfGKkW+f=8=N?T%?eF z#HTG?G1D^hqCLz8R>(tsdc_I$2G$X!yK5`wZCho2Cokk}fW{Y!Y9s*J-^F7_1_-f$ zIhjh!AbWeLS%rnp`6LK?(+nqj*&BRVoBVnoIAGNMDUgwutIHKMV< zG4Gy$!q2X%`No-DUw73QSS8#OaZ;E-qwr4a&kF*#H|>r~gY)0uK8Jj-^8MW(U=C!T z9pdXwz7#R^gJHI~Y=%YyyN)Kw0Z&uTWrj&)RKJI*O^#Z zz76mjyE3BktnMMYLbBLK%i~Hd3_AeTR-X-APA;y9MJhh*_%1yO<6yg3tvA+OKO{cH zoPyw6{@6RnINK12oc3@zqZI6JZM$;^O3(xYBDpar{?UXT)s{MTZl1uzV+;)zZ}@373%o(EpR+DU%8geFAU*Zl4} zWb~_e$ToL_GY9s1s}Gt1XQ8L9K(yqIXZ0GoMn*z49?*LT4-79 z(kSNOK$BFP|C0<9&pU#~<87SNjksU0W~FYT)qt~d+LgA?p93^-;xhClMz0sJ?Yqlg zW~fGzpa#bb(i^>8QG0c{4PS?{l34R}gK6j4dPQcm3lWu#eqGRdGfj45ZyOqPTVe<_ zj~c$Hg|m;EwF=;ZtbIh`#1>tKuCJ%X^h~B>1_vp5UgM^G@dp)oOG<}gvqQvfvpXg| z*yFfYq82^Q-9N{LONk;2r(8kLYP&2}7 z4|LE%UaRKgLG4CR)Xggox-c+*2wI0D%%+F(RrM1W2etv^uVfJ&jxBhu+JKry>>Fxv zlSLuXP75C_!imEALM!8K_e#Pc)d36#1{D?LTj%EPg@UcGUjnbz-Izc*%+11`;VOx_ z1E6TU%Q`L&Z9`B0$5qO;Myr%0mYo%Iv3V{b`u?eB4cr3s-$VCW6Go%hESV4QUDC(6 zXk5FN;LtRJL}Gq2%$Wxr#p!?(A07g#5fr3m?h12|SQ;3H$EkPdQEnZ};cpws3ga1i zSUNmRyervHB%m#_-b3K2D%6jj%VB(?4V}2qY^v3JW&2nkj1m^Jj_-#l0+JZJJ`wq- zm_iWLNfEHctQXv{^%TvpUt-4&<6Yzli%Y1OGGBU~M!seFbB!n_^vh{n3~f!B%26H~ z<{hVj@To(dZ?Ia;R(Q`}EFWeSz3D&nBf?h3F~DX*QwUOMgJAjzb>Bjl2P5i*YQOoHFm=$d8S-+sSl#6wBP6P2P;xKlI3OMnhSetYZ8d=|7iF*0|gh z?oB#a#oJ=*jtKNbM_66-jRlWA;mWPWN~htkhl|(rar3K9tW@og4wXRf=C}Axhc{33 zIIBe|lh2`GSpU-|*GDrZIANQ6uo$$Lv6W3VBhn0dg7|Z?je)nhi2g9L+oq5VU(S+X zqRwnK%CFxFiaxI<4rjaAQPOe%`dNiQE8LsI08QC4a{?RTSVM5&74c2_Jt;%O|GDIn zx9`*XUef;83faS{ zIm0`87cz74r8iMqHSK(O#2}*s_|*`6Lo3U2zri5U(Nq`wQwO{esgj<-fEZoMQ=7!42!1@LB@b=hoB;2(?+s9%+&JOI}6y+)O$4cZjQn_en`8; zUybMpVC^C{aXwhzLnUS^7&sFEOM^DoS^^taZpS63o?`y6N2Q26*Rsfg17&1${w-)* zm~QcG{E4o(c>9AX#h|YgsHrFB!QMHK{uGou?xQRr3E~89p|ONE#j?3n4gckZs`Ac{ zldz+L_0ZP>O@N65pgkhTXOHL-BhNEgZn_FWe_Lb+%_s4^w9Sd>%>vW#s$2_xp@9G*`*0s7`jGP&sxhz)lxWe(vSilx}N7 zE6($nT+~eckOyX1@F56fCW(y#03ltslqD3KQ<IG4Cr!j1npaqxJWF`1#|Q$V2G?WS7TU#hF`WMWZ}ogTP(Ah(A#^FA&?v6gVTE` z)dH+uJG9kdX)G_IyDWe~Td7M#uN5x@0lhL(4tLUuui&ARzCKhMLcN1GbBFSJUs5uJ zf!HrrU( znoRIPLutU;H)>UF*|Xh8ykV2}VO_V~%affMcaY{nuMnn-+(3X$g=xDNVM2McQk)K|Vk1 zvSi^ELMgtXQ(g=I;55?l0>6lm_(1uFl}k=N@+Xcm3DR&Ckf?{VEICLo)1xjj1D)&w zLVQrqT9tN*7cIwg8e2Nos02;R{%8PKbpFXT1^c^`3Xmu-T3-$SvZe~w2qiRdivF7= z01gE{aj=e227^zwLq(ly<;Z%B0t6Meu$Xq4o_U^|P+rXsEk@Hby!cN<(0L#C2%~PZ z_&^=3)N|kszCVFS*H6!Q5a3!{SmWG|oF>vgr)=KS*I&aky9n?1@YG-$Z6%kWh$UkN zFCC5k(Osb4?_gW~^`&{c&zY&KkAU)Lagdu)t72@oM>~v#hs(Ka4H9i4fKpE9vsq@e7!d?TwMFSfOjE zAnz>tE%pz@necuf9hAff+AkYQH)W5=Dbu{#m$vnV@LD<3NNdglPlEe_`12)sA_n=N zJlqIkNrw&_;u_}FUDRrDN79-HpU-ekL6~pPjWSEoj&?)6E>U+0eKf9Am#4T`)`12> zu(PE!Ih)7OO`ixS{VXS__?IC0dLSp8S|!2f`}p6_81f7G_qMy)##~5-)3{x9|0GE0^AZdZaejl6K1OQc&fL zO5jo+9t=N2_g7at`=)~Pfy48C>B+mrG;)0%;6 z^Jok4wR6p<-ThX+O)%&2pWQgG_2MSO8QAGjlQQKp{eW{D{h!EG1S)>l!2d!0nhySG zyG*=uo2U6XCi#8W;=9fS+mE~bQ#`1A)M>$O1|IGI732ZzhQkt|H?V3w&oqPmHcX8x zuXAvM21ZPA$n4{6=z2^S!f%wT3`2Z;J9a?uSuk`{D1en4;e0A_q|IgE3pWN$!i2DE z(ws>1l+pR%*O=^)?emX~wmvZ$*OE_*(bP#R-tthbtcHcN7F-TH-*dPZ&UPXm&qfIt zmX}&BEdw6}qol{(7kJ8Jsbk8}a2N36>|<^s4wjazUn3IwqMk=QWUSu5XT;8mq>tn0 z6$4YYhh0K>-~PH4p5+mt?h^b=miO#Yf78*a-&#o)naK%0OB&azzxuQ_jnv%?Z6slh z0|jev&^S@`I3Db|hgLeR!0GAPS}zqHTxa}-7DF9h0s1am6drCKS84kKfkvCuJnlzS z;dsQ!HuPzhMCAY{5feQfFjEi*;!M$_gZ_8jIMQRCG2D0UMBBhrj7kWQ=NeH1Tl*}K znH7gLzL_Bo961nT2WB2CX6X2i;M~_1B_;Z4n^!%;+z!gfQ;`H!@u(K+`C4kkZiiCV zy3(W{)y*{NBPV;_lB7UV7n%tu&x}dTtms zMwa5+1wVo!3I?7kszVvlEn$G~F}I$aQ{O;;;1nb>uu%dNb(j^^5op}?5T^)kghr*?WiRT3I)bNpd>*hL_D3O4~>Bnn~2 zzKEOrl&D|MD0@|2;4FUIzEhhndioyHVWUSsil4EnlIRWPD?@wx5(qt)Qz-~yjWO(L4w=hVqbw1ikGk z*;psr7I$b+IbE}($gN~BF`6vl2qkC;sNi8b!?GKr@iy@J9g>@-pw<&X$WkLYIdbNy zkvLFwROe`8@2%~0Oh8>G#1qWDzq2J?vep{GYX+Ss6Kr|k!^h15yfvA1oV%m**%~H7 z%V6&wjSzbX^4Nf}zT@O?ZksqW?KKW)65xPjjM1LIjxW1t__iE{JMkSEV{eb;iW~~3 zZmq5j`PNDKV<|Qy+rL_Vmx#usveLi>UrSXoX$`rx(cX3qa!7R<#!XgJa!R_T-Z&UF z#ojPQM60@p#*s1sIH3#@mqs5M!^HX0{4@cr@VmI&Es=Zf@2m1(D89EiNXSQk-D%`<=&Bjl&tg{V}DFfFPLR4f3+F$X<4V3sH>m z4Sb8myxCuXL``jDwwvn|`=ocky@iK83m*QZ|F1bjjGvlNQq|-W z7@EpmO|uo~8Abu0q^1lFRUj5=u!*6-Cs&HHd17gE2qPJKaY~f5oxe_YN7==8@)~tA z_26N^cQ-N+8Bdh&HV3VIW`JMCe$09jA(eIUPq}hk#F$i#ii*Y=bJ(}~EMRRUqK&1| zYreIB$a2*R$=doANA#6(IUeFmI_`iN$lZqdI0}FRD1fK;)#tYS#Gz{BF>Fvx01Mn- zeMzt9^e;#g_p2O5Y^Q=yf@hNbI8delJId4qQo1pq$zYOK>uGD7?`TMR*5LSKw9zv) zW`=53;YVB?3Id*8-c;RAie@sJwS|5e4z;EZZx_0qlJ4Vd*iGDyxL&>uEhbK2X>{ z9xuA)H?eQQA0DA1_8gUu4s?uasc^6o?_-VF%MiKWIxZ#4(ZZSBuVbJDR_xK@oX}+E z5WEi1?Eos`hdTzpOrQW)q^R1%m9a*O5^#RC7Ut103?lLp7t8MUprVi5`wZ>%{)6gG%*VBu!pcp6y=CfpOJ(cW5V?Ckz?+%RC_+xQ(r)^PT zU_&Xys|%9tXNga}_l86xc9$?&ylsPWVNYEE1l`(;m!O+VT;I%>Ht0)M9^&JIjIJhQK$iPHYK-Fz2sdPESqFLCNAk8$E2 z#RD!FhKy*>F_+es5`3#BTEzKrG{DgI0TtJDi7`R@G=rVYA}LPw=Jn4fXn@|do$#_t z7`YGAQtP1Dh0R4*`pwq|T$yEuNu^<}!&N0wQmzBEsSUVjup*~tXRTFOEvM;l-wa>48Va;7%5RM}a2Q`Ler(MXuJ4-ggeZw3Le#Oc68{AIsgYO4o{N?cB6^E@ z!Zr+Y9p1=25>tpyPey+?tgOGO?7eS;%G(6U$X21RLyD`UZ)G913B z4sNNK8(fVT@OfqdwiAEiCsh{g80Mj&6BPjMd-oMv zvSoG>xHHtl)1;Qm0PpxmOBpHeFb&{sRi)zOteabChqbR}Dm)@Mj^wNEuNm=QOA-lh z#N!|-)|Ue}?6VBKU<9ItjVs0x4LJxqlXc|fx}4|(dVMn=t|Q4dP7CTJ_QfF(_lWYX z|1_Fqt66>!-4i|5t>bLmw)(G>7K#Y&?Q?fBhpn%G%a-6ade#isg0p1)qVdQexdtfk zX`Ry~`SdE;3LHyMf&Vs!ml-C{j=eC(3Kx*HKwSVD;NdxDS(*{g%oK5;)P^P&0rY)4 zMG^lK*eC-(h0tI%hY4x7Xxxfw2Vyt;fk5rDwTkEktN6V23RAsG^Cfw{1`6|XkJMMo z2=_r&w(x9s-1Mr*6)Vj4qvF$n?3Qg4i%3KeaiEbHz;g0Ki(+y`&^|pi~cwD*nlQO@8ez zH`;e*X5L`lpjK7T$<=41l4B467%wuw-brt%dN8L1G(kz!yb()TZpmqicO1H8-FGSM z)7ci+%llq|^8(%#I^-w<|YcG!ISW?1~|KV|FHx!#-TM|vFrJCS6b4! z+n{k=P+K@2_Q!fDf8@|*!)4AVkUe!z2RMoL6<`v4vhHkL@#hJORVF0OU1AbU!4D#` z?f%XdcAHTJyBIZ`g?fC*7}vtVyhK3>V6*RF!+#EAMSyUf_L%Jt3G4E^8$am z3yGHv(u1=0|G=4i1$*|yMEd!%#I?||WJULu+(1#3SCkmO#RY>|d)kHJojxls-xaxZ z-R)2U6bp?$55Hq~M~MS~J$7_xDvz)C@%qI0$h>MY1h%FlT(!zqHo#=H$@Gz~LY=N1 zfqdY8M=_6yplQbe1JHEZQ^=*%H^RcoiC9|19t?nMzh8yrNH<@1tfG#(A>cq(8KpQs z=!c0y14GkI3K+vCkL{L*J!^K7twks5^93bfEapFv$h=pBQ6|yRP&^zRG0}Hj#k+X1 z%b3QH5V)1M;1gahGw~e%bY*_Ve37Qq7NM{{KkH%pNXcbVEnBl31-nJ-adNZ zv6n8r8!HQt9Rw0S<>8e#Vsiac+;a$U z#mfyiRnL9s)%jMoQtaH`HFZRR`THCSy54X ziIHVY4qW5t7iZU*%g=#7PLVcY7jdqSN!u+eF)d#Zgr8AttvId5CjY*$%er7%D zmb*FtZGfTQ)rLXip+DKDFduK9jr$OPfSR)EOU6RJS;L`&)VoV0zNVF8CkR8+vP0u? zb=Ti-7bnG1z{$LD8UqH^)s$_wZ&%ekqO1A>^}XZ7e}^Dip2)jSE)|ekVfG?cG&m}w zUPzAI&R@)3K-7ks)|D!aAlA9;;^g<48VA57 z2{%vugxe|nptf1hk%<}$#MPYdQQbd*=Gj&u-=s8ijxe7JjYP6FIr&xW9xU01|6E6p zvsx`L;~>uUDQq0;@Dau018d)<=>`tT8A&84JLSbT1J^l#gRo8H60YVb_|*u{{t?<^ zh5)>Yv6f?~_hGkab4>l@vyGWJ22v(I#P7Brfl+8G&%F~qFOZ$97oZqW7^EFQal~&+ zl&T6x4K&w(bNdWsA(4Gwev~w6e@AHb>~STR|EWc_D~CX67Uoavg*(A~bW5Q%he+@U zmw7?nWoNdiz!Vtx!0a1+*fxIa|GNpUQ-{TwfhrV5wQuJ?iJ-9i9PM};pL@q<_6y)+ zXm=_#^+4JrJRg?(@?yChZ17+E6{??#@sI#~H4o>M_|kI}VE>s5u?a}(rUKDTha&;K zn>_m|GKZ$fKAcNHMO|YYfRNGNQ4C0RWYVvC?fRq+oX0X_vR||4P?~)Lsj~)0^qSGXzikggUK$%gKr6)A# zNf?uA3^oyPJJgFXl*rHF+jKjB@~+?XC(w)4i7Z!n+&;FPC&9(7rI68keRQX^0RI}U z*eF4u$*TVs6|b>t@p7&{L*d%3QnpLn5|?bkl^shwH)JBhv)gxJD_5C5w|e8|^uJ7h z;EZzh3rhAr;-fEKI<9PZNr&hk!MPb8W$SelL5tqWk>EZkN8FvmR7dpv=h`y^kK0dI z4NFvPd<}H(U7IrB=VM4ZS!mMN?f3gQP(ZZ$9@U5T%EjSlmNH2Z0Fo`R8gsLQGeb0v z^!UBk8$Z!G{3f+Cu#FMaT%Z^}{zE

0omo>04vF7=GO9t)159P(%WGY=asIFiQNs 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 z zs*RTS-~tSLez`9CB!kp$UN4^3`0{2Hg>D9Gc?&F~Sz37F{QYxoV)vTc*$yIiMSKlO z8yh5KSJd=;e{0Jf(KUwNqlYwYkmmxNqauVRlO(w0Cr-kMc{8(tegu}oE^C0_7?pZr zy)#?vJlNL1;Jr61^l8VXEKL+1?WvsKCDX;T<}k zm7IyWB@nSIFTvZ+dzY%d&;*iWw^i95-IX@J(ZNRLIeA%obFu=O?R8#(TCR$JEe8ui zvJiY@0HWj!49-m|qO{vGD$Nc4g33fD^*!N)$+uaWTXDji(TVhA2JZ-6yhy)00p3}{ z%B)6{oQoo>(KDweo%N#K!b)vhfpGPOSJ35UjuvMIRI{K0Pa|qvS?TSf_A$`Nk)ecU zD3dmXa*On))n{s=p>=o_LqRr|0sy&tvMaHusK1}YkM-dN@^%LEcidS`%{cXYa_7a< z12GVF?uzcH@@{5s#-Dj|LeZ}tnsx=5wzQgPRD5aO7S#Rej0ZHvH~ay&V|2V>(v^(K zxJw!7hbF{0t>9hG=Xz#rE8<=%d0p}U>(b~Fn|;A5`o}?}mj6OGy-mLp?O4fb<^-y4 zJQJ{wn@d`TrG4z-i=PrkJ4MR>6gqdh2srX1&Wi8@pdziF_dS4Ie=^BW`)B>o*URNw z4C{C6H)g&is{R~%4|8p1NM|$E^P+xxMtMsiZEl-hrG}EDJg%KqhzUU++51CcBw_UT zTGcx!g$hs30~183yRnQ(7WfRjC%67R5IV6>6fhFJ|ATL$2nu`n)HPZ`)8)v$gdaLY zf@xb0_;nT9eOQKtLe2s3OEU0jOGp9?P#;CqMA;|7SF9c8VUEeJ5nOu)<1WaN;>?d5DlG7M-y77EuMp2Gj8t0 zu%jpGA+`qb8Y8}YU4;)`guPS~$Do_uYw>UT^lPu4{vfYQ3MtC0y{{UYgyGF-DWgEM zCPyMvQ9@eo`g^A7wkcsaJ=PB2N98XuAgdF#qduGirH@BbC(5<`7F3ky)KuV7g9z?!SRK}hNEgn68R>sO!)Ad1(JF)p2rH9k=VO`a4h zq$Rp8wUc_yqlpC_JwfJNndqCGbr`+@K`$GubM5xTEVrW7M4sQMZYo4CFKee)PzX1o z6QH5ZZI~H<+}j1MuycyDX_(p;j~}45J2)=*c&uYPs6^MV$JLt`qad~+n|3BixcrY_13LVFwUHdAwp4t} zpRZwFRLr1D6^{o(Tsrs%2i`OmYFq_O(;$(nW|~VC5Pq&4WNKaoDnt()pR>m9C${10 zYX+)#ZXTYtCJ6DyM>Md@3T&-`4qdk4z-TChy0oNr;qv5n!4fWUaTykotO$>FlaLI)D)ScoEnt(zc-$tk{)^2;4=@sdc#dWCD zb=`>#4kd#;u+T`b*Z>(zY+X$FYZ~2Z$sC8wPB05OI+uf-6d%4ZcSx*P_})@X$Lk`u zJDS6el$#6sWPv%&kWXmyv@cGWP3YOwo6)adb zj`)KC51;C3KqEhRkcs55CM3fLw?!8xd8j6?NEn@B;A(IZc=`E!*!}*UQavPdEt=NRhZ&!u&S~%{ud2%4MoP#k5R{rI!x0;rAOci;(7976}|X z68@pk*7UkRT$03qb1O02H{GNiVGO zrY9nTghbA-65OC7=*u579Isp6J7geA|j4s4io61oH5GhDgBc* zn5$=TP=crzor=+6aLOqe^oc z-?A@COY^@9pUHA{KFsRdkaX1b0xF4&nm5&kl>1<$6~`alr*^XtIv>+ z_0P8?0d3Mopb@7Zrq9O5_sAeq>=;IHv zRNBQghVHFcj`+%@9AHT!RO3~15=m_fkJ91}JcB0#6W_twj8$yFIAlt)0gNF22^x2` z+(z=K2NfP+OvX#Mw4agt;>jXBns2>uU#Pv?*O|PKyeI#=|_vr>5QhPgiAjm5MCe8#Su@nFGChN>7n(KT~?fsn!P+2_mFG>sv zs@J2aU2f2L%6aMIB0W0M9cL!Nn_lG)Y5dCSG}qzEl)A~fLrH84;gOb-nU>b>b=6fk z$%aiD!esiwiUQtCWb9Gv1<2FqXHPpjLc#(00@|DyQmqI0sI2=AOaD%*gP#AEePxtT zadOVFW+D(;?!c@t_#=5}>v&ns`T4b*=z}$7;FiT&0|hL2XQ5;oRRa?0O+XvG$E$NC zFx>qOmF&Hnelg@VSANbH7s%sYDz+YCH03_wa;ROL`p^etQ9G2lKC_S%QgnXp^LD66 z)g}&~lHUcW*;5=MuVWT*a8!2R=S)cFC9rvBEfGaM-$8r2mT73V2IZ!toGO_kL|}0( z-63vEq6*g@Qk7Y+AGk2mBH0pAJ~nL;R5Gfsf@ym{^+ez# zusvwhCG+*hS*kQ%Hh?~OcrCh-VfO2Fi&H!_C8~0!R^n8Uz*JaiSTD@(NmJQ z5jY}`rZkUm(lSo(&wg{E4kv(jxNf3@VFrnKLuF*JUxPl$raQ(Ckm zTpG08Utbfkd0VSH7_v)XJFx}K(g#X$xchU+H;H6UrmfHOoBpSFylWdAXAJR(_aS))VIg zez78?zhxoNcfQR2&Ka!}LtpLk+VW=4S{qo5K<{X3hY5NnPF!M1*^d$P2QEZS8s{oR zN;r&o3)`HV;3YQhQe*>Gcl66PlIb*N>N7>QO0DfFT!s!`7PBdXBCYRJ+T~-&x7aEu zIZ9wv!wVaArV05iWS8S2^i9>c9@x>xw*41twR`b5R-Vaj-FaGc$lE;BvQ| zFKDC5aj=SZA$h5EnwOpz%~0- zz5MbMdV^_ts9XY6NriKuI|^=%KW$FNvQMM9BsT#6G8Ob*IHgiODy#+K#*l6!`i5RW zX_;}C6Vz*L^P{FGFwEOW0=T(R3V_%dRz%R)A)0sc<7EYR8{^V#BRUjL@EvZ8P zi`~`O$i6iVAZ5DUpOX(r*(5!NigMGN(y@_`o&YS4J8FFVRPou{&H8T4Z@X4H1Bf(W zGU8b--uxDP+d$8&=}+M`wKJc71t@)?CX1ucmv230NEF`jNp7ayztD4Ol0oXZi`S4s zZprb9I@Ft4RLoKBdByhe+BC?ewvb+NqOf#Yz-gt{s4%zPV_d@dLQ*i(?nbECmiZhS z$>t;#c3&H+n75QbT}UVUr64nhERj9X`^v&zsVebny{5!!EG}!^Q#htdV_0Q3R=G*d zx)N)Y$na?o>h#T9%hW3vIfqH^(=&K8u=n|B$0I>xPGF{8WK66|^=|y%MJq9w1eJP* zvus{*$v7>$4BL#md;HOwmUXa($JfsOJzPQtrs`PM){OqDogeS?3&sRORf{Un9YZi% z-uG-YAddlW{tz62ePXs;vuLPYrUKY4pl3iR^0MUwR^4<0`MHH^`Q56F$Sg6xAB zdH3Q0T$NL!GBBiwb{kzK+2e^>tlMI}gU0EZpRRU{P(NXzp6ub^P-Jid%Do z_gzm*dSwsdxGDIpdh_8!S~Vy@?-#LEHp)FsZRdA=b?H=%0+C(sQ?1nPv>avYHXumR z{7Z)oyFEpCLnx_(0UqAklbCKqpR|C(KP*t zY;ZUHdiz8V$wuuL1@j(}Hu7ASD%T<1)wdXyK)hhp#?Q|~<-kZ%6^Dlj;5&+D^8G8; z*O`>;q^w+nN3J9-{K{n=0&X^7k$W`5cIHCDU5?^ zYq3v<^&HUM{VaLmA9sE9c@J%+gbh@}W-n&(Ps+P4RuRmTLt+Eut$Epc5@g#Q|ogUM$8l_i_SCL@pIm%C+O*K76ME8tio zKT>XE^3o5S7URed>y^ZX*+|jYltWe{+(G*IW(!2rcqIBb8)=O)S*S$W2I#fK$Fj(X zU}gFY*T2rhPkX}kpIOx&><<0^t}Mg>FAwzO0Wm>II0x)3{dL-t?R; zU?OpEgCC^tSvNW${VcZ_SLl388v3}5wu3H?%Q2vfBJ{545}V6iyTFyE+92N%CB3G&m8E1hn>k4OkvJ61E?CcR-c5F^DijQ&I zJ0x@7k~T7w6!cB;DYHY}3x{VdoT{J0Mtq}4%U%W3_NfxaK_rY(Ps19uBavD9_v z64S)?gGv6-4kek%HvwblU8p1jDG#O_V zEuCtcd%;Ku+f%x!9!Ht4C>{s1AFxuSsw`zams9is8U-E+r6CZ5{Ke-8>hCJx<~3S7 zT|^B_x|inTusoUWQopomD_5Gts}=YWKtxWh5n-Ber(UtcbT%jvt+QY?yFLT}|H|Bd zqPix%hCOcmd9PA#evyKbqmdy%FYNVXc_Ch}oF>e_0}<&X@Sqz(EMfctRy{mY-sHWo z@kUyoiC*vv!ooo5S}B?0E2l(MSQ62UhcsL;2rBFCo|`1*#%Qm zx?+u+Q7_68o{Zvw$J=H)`f+;0q6U`Kc1YM*DnrwN%s>IRq_q=%7~7Fy3uYuWf-LnO z?E#i1E|b@X(#}S9E%~@=c+J-Az``WmF&Zk_qMx%Yw+Qi(%(IJM zn`r9FX8*EwqL*WcX=m+JR{-bYQVe-+A>~URv=dc(CpF?@y5H+9N<;Yk&Mxp6TG)Zs zKJ%iFT5UBVdGU~S`Xyptqj$v17L5+S$)cu zk-e)w1Jfi7F+Tekoh#?$PCgLECPe$l2e1C9>)bflgl4qXCmlQ5%Ue&-S+;cX{(}XK z%QBlzMc@>C^RZIElY8x(98y=|b*&paICx}@yl-ET+YP^s>6wxzhZ6!$+GRB_F!#d= z2nXHoyC&Cm#TltD&aY&Q9znh6r zT!k6Qs~H8QIIp-=sK1o_gt(9>@t0M)?px)nOU3EPHmB($f?&bJth?cv{0zbdx}3F% z3cFc#mwiq^@k(h0qOA&c>BW#FU+U4))N)_1Z2w}&@T8j`<01d{PFRTu}y6kPC3{`ip@E#m(%Hl~rgZkhQD1s?~6v%r#! zs0o9XbbL)Hq)Zp;7Y#ZY1~^RESB4Y#$w`FkTN*H}G3Z2n8g=s)Jx#d)Na*Yzum$fsQC@LO$9Oim=BTrFMPf+d$i~eNkw1Y2{<_6cw;8 zH*_C<40+LFew1VYK#O7>i)}iyE^!g;bKY2AB(?bD65;&z}#=M8GSW(5^A900uksMtpN$_(nTF#c?#~QDCG8mlJWW`NT#etAP^c$76GK!ZWsAQEaVn6Cyhmf~-R2s5s#z?D^ zeqj63{=a%ekeVA2s*5!Z#XLymv}MJDS$Yi;n?)>F_;w zU+k@{egi_EJZv3<%MAKhg$%IRJfiPE@A?^PwBQ*f2p0=}JUwO}RE5Xbc#o(v1OdBZ z=ahNafczTdL@NESKw=t*q-0T_>eTpaAfot}~|)54&D`Xa!R65XVVF_hd&7Is6u zLc3K0=FpLRE_8#R^>~x*zipa8>xodWfn0}J;d&v|5>PhYY5bhYOiZPeZ~O! zC_Zt5n7G=CdD#*(4m?lkaFh1>ckK>L4t+=Gu%Jk_T&U~q(TIV_YWy&x z_SL3Dk#E%_JUy_HPg%QQl=tCbHPp-qRi56dSQ{mzmK}|?Krqpdz}j%!l~O9oXfIsHDd1iGz`G=Y|7v;B4k+$|#T*0%EPVKd;_x(1`gm2k7^N0(yBt zfI)Vg=e~c3r*B)j&-^LSsA*uv?%yiHqev89vwFbvrKPr9aq1VLz7rtm#h@P{GA*_9 z_8^sTZQ9jpEa9HD@*p5Rp(RzC*n|yI&?`iIyVr$nMtXdZqPum*@BCa9m7S&Sj-1IY zHyu$^2Du=)@5iF2WFvsz-@3u@qrXnfS@0NX3(oz zIGB^B`3~*C@+;Lw^sUTS=bAC?@i~#O^n&J|;T!#Ga0eTT^0UY@S?-}=V?GgcpzKgR zGw@`u0kA>YNkLLBU^<--lkr{$>MSex!Fg>(xn(P<+~El_v49BGv2MY5X0;O-y`7E$p(1s4cPMCX4 zj9JH+8o>eWZw8BrZ*Ze!?aM!OgfODCyUGYI9IhGJx{6R|Yv2JJF-c;VQ7vfmj?Q9- zB)X*iUNc0`IfHD3b|Iy^Y>*uaI2pijX!u*gWN{P7)cQz5URV(^QQMF+?g5UiVP-C? zoygi+X-nTFjukxXb#xi#4gKWdQR&9*^%XVp=SDYb%Gs=?FlD(|DsIf`QL@5)13-T^ zU1PjK2_Rd(J_8~P#l?)0eO5wAlmvM(5%+ag@sP9YiX5}x>`Sl%MG+Lmxn1525K>4X z*Grj=U++KRH7YfCQQ(^hmhF=u-_c8=(VO-MpoA143?7!~0=|>G`>BXOy!YYAos>csP@k2R%pF5M0U>=!S`-qYwo&(}Hv`fpn<-$*6 zl?$SYHbrQgGQB5@j`5N2q)&@psMx&6EBsea5zlfHL@mY zV$hIN6eDAv2ps9bxA0c~Q_c-OHU@zvdgvsis?9>)_f(&yTJgHL0LcM4A%lY+C^}M(@ zFJ0n{2uy?uZcEUwH~9%rm9(iFSUI9=J9!XTgR5)0o;b?A0M{+_*e_|hMZqDtDY^B> zbuY(zGo5_^|33i0AH1gDU^w-=X;|O^5u}_QR02j4TgStBz7itd!N7U4?pQ&R9_)GbX`L#{)N@AF$5!wCJ+*yrr z5rQqf-qOH=CW@!W)JH4cWS{NEZHL}zi}TT-!hD> z&XT^@|BwKuLH!RaRf}+Ef9g<$C>KBA{Wn4*4dKb0Lp{p(S?Z%)5+1GLm{}h>oQ2@kwfDim*g$A5_?Z5sJOpTnn%)|gxB;WZs2&d( zFeKScjwS24Fe~>qyvUUrB*!Be5YTmxV{_0#{N??4Gdnq^I;Ctu{zftM#w{VlCdV^( zS$X4XuB1TZJM;2!&D!@Ow0V{j7;#nF0jJAfw=kR`WiLZtJ0IT8>tzi6AWCl;*{qi- z>(3rLv`PmD%?e{NC!(p|ar`ZRf#p2Tlg*+T&}5fUtROVQ<}g7~33|9X{;%OH+*h5> z0q<4Sg!BVM%tZ6rCEdF4A}w8^z&>S=KF-9p!eroHWoz^v>d@ba_k+PkHj={xxTuw2 zwWm44dK@xCFj7R2B;B65Y=qSoO#u-t|GuF;;wZc*L zPm3Y6R$m!Mml#>QN50v>#5kRja?0s~q4eN%XWbHK*)v8%*_st&eIMcY2&GrB?X|#N znx<$V&sPlM9d9TMM&^ZnASVaC9xxNc2p8@quPUh@x?jjU=?B81`sX~*J%oz&-JStc z;xC8KYri7e;6&!UFLavYcv-YG#Z#QIBl;H@W^)eVqco zG}`vSAV5GA+3MVFAI`N+-=l4NjhcAUXvG6rnHUuyuAQDe zE235K`JH2vtJb|GiniGHK9<9M{J8~tqUuJCH=-^IVKipwHkep#OIBF(3imvl!fl;p z8=4vzKFD^+^bZaQD+=^b)uzt>7Wu_o+MgC~6krS0Eu7_5rT1I&mCJ$Gy)f>TNh;CE zAFa`QIzg?klG4+du%0GU(Ufe6*r@y3o3sg+1MdJ*$|(GEc($S}?LyGxh&*#v9DZv= zXBC8Z79j<6wTk!mPK88GOO+^7@%HswX3yh_gXL}Ut0_6#mu6`IUjR8UO(zS)MBd?+ zS=2urm5j2vuJu%jn4<@eQ$v1(Bjn=pY*R=wiMC=^!NM?i2fFNmuam;UXc6%kkYp+p zeUCTr9d4N;RMQe8=^5N6KXbN7;d!y8qJstBx%Vn63TI*yQ>4W zTSswEF*qC=Iq~i0<#(Nh|3P@oc4e@KlXrvCi`9R*S71Z${?jtA*H5vB>&2br61J=D zj8iBJ;9ai~xg7+ozdnL>{2g@GERq9P()#92Gp57^HjX?vsLl?}UpZQ?_A`;+Z%{jm z^x4|%eSVBUrkzI=P<6>ew!@kKAPXm?FU$f#2UX6ShntLRk0I3Gd5waG<{68w%2Yh( zh&7Fd%^xH9KRYbG*H%|_)@zO*Ddyc7-M#M@cHt)nC2f`_o(UzL{$aNXsntr^fGn_i zoZ0aG*FYQ^>Hp2L$T(Rf_D+nm29{X^Uuvj;fjm_QW)RJgH>#OS$5KIkRg$vN72sny zMI$*QkqQA`m6H<>Ub1f}riNLIrRS5YVqA5>PC-Ly26D+%=;u-2G6K-vD4Nb!uVF^t$I1a%JDZUEqO>tRPR|voz>v$rzr;T|5LYGzOSLYHlaM5Zg_E z3A6&nBE~$<@UN}l-DG%gWxPJQlTE8~^kv8_Fk=R~S!^6aj(e zZ=Qbz$#0x4pq*bZ#sfc8dGBSZ z+i#n>fH+YoimU1JvQiuijM5i9-@UUX;k8*w_@$e=p506MvR7 z1Qt^RTg9+-Z`oe+AeHr1Idk0&M!T;=oc32nmC)u$o-Oo-C+{MbRmJ`&P_I=hK_XWja{nC?s z-l(L=7kfPSoJa&MnlEZJ)eyp&?}F9irGJ;UPlpH8lz5YLR2IdD@KoTgfJ^TroMeen zb!d57H{=!=ASncr#f!{^GJzFS-$;_y| zg=m_%)U&_gxW4GXV@+u>dg_w`Ap^BRgZ0A!QXNMSg@`HP$H$mRQi{3#*$xHLwFYj7 z2Bsv5o0f(RX~Q$r&m)sL1ew4Q`)e|Ft)l?Q{RN6QiLW*E*DrxD_(<}FT=aG_O&;ek z+lHls1?rp*`e80JT1wj$dq2y8UFy82fu7jwR3SYphqs^h-`);IVMK~Uy|wTz^rN45 zZp~P2Oj!cXK|+v^7-N-)+bqyS?1IHD`aE2i$JfZDJ4hF2M}O;QI?(r_XIrp*CbE8Q zwidkH}o+L? zEg}ipDr0JQ82KtXhQ~t)SNoO|-_$qQ9d`?s0|~hd77+-x*nF-BOK#L& zR-iAi%~D!bSTUPA4nQJB7y5pe!j>k2p<=I3+Qg?g^Sm}HV5e+6Ik#zkqTjh9h?M)A zR+=Pyyumh?iUO8pJuCz2%jb{N^%komVwOhx`!mKlmiCgFt7 z5mCi8ZGf^Ca_&b`*@kRN;1Zqjsrb*CzE5FIL|L+4;*B)_Mk*0ThJGm~}&boUOmop_i?(zfHGAT z^H$Mps8Vbx^-cnWVb1Gf6OD!_IInN3)|>yM1)vldd(;opKX(Mv17l>uFjDzcWDaGd zjBk~vdsVBTFhQl9Oh4~ZHSUToQ1yJcU_p!Cv$o;XC|Fa{*({9>`beXcjyqt9o&Jxg zFvZrjL!E|$r9Sw?dh^eG=>)3B`B1sR{2&A0Xyn(VN)dkv(AleY#@iFj26m~x!!wAu z6QcxQ5f293wG})tnT=-$@%E8+hh<8S6whDuwbF z)Frl$jXnay!K=c{3-AvpT7io|09*Jiz{qNea2s9ficV3i3M43C7*7+e#$9%YSXS)_ zS#mD%X}|2;7e2X6gMQslDplb3)#*@Z19WA_AZO41z30%%Nj@QO3zLh)`sc`Q8Bqg> zc7G=_)lvCVEOMSk-aF7E-j`FX*o_`Lb*gA4qn<8DR!5rl8_rZ~U_;s@VREM4tyf{E zzkK~^5iB`a9<}eGRC8q)8o9X(Ej52Zt0`Tf<+$E{f@(~B@W;?Iln$sT%^)XfAAmM` zTwyn!D>~R0IQ_&FswakD=hIvKmEwJ_F$-izL>ndDj^4pgUPtXoVY=4w$GMWXwF$-G zW=~S9`xEg`K+(w5Deze}qQzL_67()?!DGiHzC!U)&&$aO)Lb|3%?7YEZlV6l{PCKR zvVwsv(zvtLx9d479?icDgyNp*r_0mgIvkbm@&KX=c$<1z`#t90^}#H(@6Q-KPXYI< zzE!WM)PV7f%mAmDJ_Xpz)&2zqs-A8n@460_@!zu-q5VP@9y|Mi`_rBJg+oncU9GX_ zqWs?VzUY0Qjt!Jr!-=vyrAX97F-{6@lEjuJc-!(ikQ>8X9|#{#o$19`p5j<=Wf9#7 z_~c<9^14Q^whA1$Fy(;Kicl=6b%M{UM4W7MI%7<)MRl7*@hPi65r?JqpxC9Pu)Jha z9)HeGhH;6ox^KR%X2a}Qt572O`96`s)_$dTuLY|hEE6pMdpZ-gt=2d9W(HwpY&U;x zT!&(Mqx!hnl%WWc$jOd_6QXR=Pe^RWTj!G@2&5XvaZLNH=?HLsfLSpP6Mqbb zV)}1e8?>wHY>}L%)XVKR7y9bK zlL6b11Am1{)xOvNQ|uw1N@icl!FB!ZS-WxyEt=LI;zz+X7c~^4xt5^72L)2l9%WTW z$fXoGFCXK2xT*JJwas^C<&_V!60x@uFYrld?p|n?#PmrVRho?sSaN_`q5SOqi2nbe zX-XimZ@=&fRJfBIM)XRjqkK)TY^JVoi8YE6Dt=4=n|u>1O&4=Dvp{l>A_O;q6V3|EZ)h;oaIh;T=kOk=vsau+u> zy-oGRd-L+&WI&EJdIUJ5xwao&n|)%gIj)G5dIwp=`C-@XncpfFku1cxJxzRHm!4fo z<@7L3$f$i`7;gVd6_Ms8M!gqUR&|2AB);E|1VekD>8s4|OnodNx!~VelR*Mun{I4F z1S}d!tLZB9yTmR?BeAFf=Q0GgxJ5J4_#h^lu&0I#5~cm{9v`|=+C)a_5{=`Z0Ak^It~%Oket(-8k+^I16V&*=R$QMyNtLoxzHjo-ad|C$-2G}E+DFvc|BRwd{0)}{6gaN^oHt2f1Yo4 z7#_xu8Hf#TJCR7^f2Be?N628h0zE<@OA!%+d_`{1Kc)n|<`J$TsGHs7BwNT2wqeruK>+En(mPoc9NfItRMT&gNr+s@G=Vp%x z7-f2MPZ_@@il*^;O0W1VQ-JRLUq69$cxJ;?vfF0UQ&T@iu)8UJ^#JY#7vQ!b$aO|L zHORxhqIK&5=2Fjp=z{~>stc)`kbP1?VIB-L@&pHr(uE8DKGBcb#7WXcG zdVn1nCVu$W27`-RW3qe2 zw0fhnL`L)>l~mJi+VE9iP_3;c_?~GB!z*yFISj4K=m$AU8#0^o2lOUNqW5khz>nOC z^X6G6=HPv{K0FEIZ_-%4{2eQ}NXpyFO$oti@D)96iII&VykxQ-9LIf)o#H6`l}YbS zb=CJ|EMGn~g{Pqv8cj!Ae9}4hlcQQ+Cs6I`l3Z&uF0!c%YL+cg!^e>F5_)j;v&GyH zH~9O96fvZe&2RQz@E5p-+W^f?jQtUvW1nmr@O~yPhrIjTLjNZWBf<)XIsh7lABg}a zd66rRe0O~$nL=Y@rfwsfdp4ldJ*qU&5>8&nhm(L8-xIYT0v0 zM(8PCF;OPWAngLJ47#o0!^S3#NEG87TaOk$p#&p`os>@LJtt5!V#jkp{sj>d^I`I6 z4r*<(;s`4(IZSIqp_-9xMZ6tD-VgJOIFMfxBChZ@F7mC9oX3lImSg1!yt9E_e?wqCCVs$|#$6(iojWOmP>#5#JGsys(WEcwN_?}`lP+k8t zSC*c?wU%yqJUh?LiMI^!6nHN=A+g`Q-945w+hQ457HjvqzOpyQF=crD&mbhTqgL(! z4Cyg=?r$L7rFXR_)=C8{Ix3^#Tk4^@X?y;wi8?6|Y^=h{HK(4239CZl#I&b;Pi$9B zX;%41Pxt-c>DN=4)GOf>ttL>*vCt%k{D6tOpD0ZQF~gH1J_b!dGP+)j{ptv|vEvD5 z@pZuvz*H3wIR1-zt6J2k$e?G>u44|GF?YN+zDvmc^n+P z!Ua#h#|y94(^H%ng%~G($CWfUmAgX0K=2MZpd*CWQU#5_=}#ng%1{%Vs~YpT$K}jXPsqCbl!+i z<^e=dk$B7G{?8X)+VT+S)xb@zXx!OW^8pa!{wRst>2l1F{q*QY>M`4(S|=pA%x%=n z8Fj3eilh3QD*w=Ic3n$?B>iuiN)Gx#wnSPyF#>E@N{W?Stg>=Ygh1=`ixHX?gs5&e zR~M({gxNyy17qlaLJrt?VRn>O9DUuvB(qh&DEO1&lSrE2%e%-I9m(lAB=IMZlqH%w zq-)v@G8+W}#IqtnEB?AxZ*h-6BA>55!a+cch4Xnp1Nt4FZo={ecaDP=cS8nE$J-Od_bmrQp7h0Kf4iA=tz$E zQ+_knlC)srT{^&fi#u01m3tSqqqrOnU>#VV3<9mHvAm`t3<$TEnP&hGJs!g24S2k@ zqc)F(Zr{v$>GjgN6HN7hH6dTn=Jh-^odg@+xL=i3X$}8jKcqw;C9&{0+K!;MIXk(r zR+e={I&6(Iv=x8I4oH0SG~q|-CJPQc;j^f(Op9HR#6_ZeMa}km4k>3vMu$aaRx3xf zFjgESSE&N@IMhP|(5t=eH8t{ba(J4$UsQc$A0KEOC6=y+4KT26;=IK%S$VlcOvSzr zeJuqhCodlr+cwIxP~B63_jG9(PLHm>znbHHEUaCNb3kTJ6X>LJ0R*k4Uil6L?n&ZY zDI(SBk(59l5mz1p+4hdCOxc)O7>792d|mt|vl&zx;(nZRYt0tZEz%jGZQ51Wyk3{f zCo3#*xf#a}6d)bET}mxIuWrmx(vKEbI4f>p|D9Qrm#~{DgU{w}!XMnsu&jibnnf9% z9Jc2oYdJ;0k-^OX=YR{~M>>eAY*7nElryx|H%`9y@?)TjCvba)cW*H5wKrei-WYw9 z41K=n_USqDjRji!MACTPquha2dIPg_33Q&t1%U zst_O^oRQQ$rVTgAgsnSdPZ`2lu{%fQebRzm_$HFY_T$uIuL4IF!0(6+`P?P+w~Ug= z7iiTRE}^S$Y(V$#16RKaV*%gV4zD-ZTy|Hu(qN*oY8X;G{Y2?1vMc`SV^f!RTsl$w z*Ge)6NWW;bJiSHxI`!t;lIn3!l@a_AcPrCPDCv&^G%grt|0W3|I@&_#1xFNYrn%5) z=H#`%uLXEOCig%$|8GIEGQpJFGYY@)a0y$3hsz#LVO<$&DkW=d<&9kR8~an6zzF?a zOu5R6C$9XD7ZIo1>6K#lmHrZ&a5F8VBWv2V@!`eLr53NICh`3((tvC>5B=@^L$f{{ z+5gx5P5UxE4Su_ISB6q0t@;j0i6pilKzFVe9k0q=nY27rEh5enkA*k^SEX|(bULZV zUzLWN*3uU93_)ceIMCCu^wg*zEoZqu)1~uMSrD9>_}CRC2(W(;qT>es)3ZwI5;)tq zS^*9KT)x-ZRE948o!)y9F1M=C%Iz$AM@DpBdjKy$E}dkrln!hw-UAZRCXO8>FXk|M- z_F-yHW)L9=6lH^lZ&`(7-kpSTuGEXx%D&+egiJrF?8%d#@(&d9j9a5_(G?$6WW`cw z5vc;wTh;)wkg>y zi=~P!(U86&C>%ro;^!zg!=5#SPrSUDktBwmGzkvF6j|ic0anHg({-j$A>z8#acILH zZz$>cYy>u=`@YS=XZ?QL$E8p73Sb2Ga~4BGJ&M3T=SMW}fGc3JR5i`%JW$}N3Gg~o zN0XHUC`m?bNB)REiY^Id^HjZ@ZJ+R%Va)_t8Uk1S#nAn>+Y;x5kW_?QKFrc(@v1E! zTqP{J>8+GGFcYH4`B&Q$3|t)x1_gYPZYmH!8@hzoRUh%Rmz&;f@4m!}{RQNpoZ<{PB-_mW$k!7N+IsbZ`zl1qEG-_0a6f`gMKTG(3jODr5 zN0;%k%=o_F|K#swg)269Dx)Y=^Ojn-;E9q2QWhvX@oe7ZCqXb7Be^S}y(=~zf-?Ci z*)3g&k^d^Cd*K|#*XqQd`|c}NA*V^paHc7Eo!SwXBEcT5G)T$RcRjRfV9P)D{iOGx zwXm8V$kEXj|5#*nngNSCW&Z^4n8Jj5h_d0h?a90+dE4t0H%+y^H zm18tXJ@`gq#c*1=H*(=Utr2@zkM8ClQ*?oyLt%h>Bu| z5kZHapSd|^!xi2Gp*~QWhG{f+StO(U60_V)!Ic(e=VkCL*vL)w`zv00?Nq&|@`*FuOzUSY4@4uLmdCdU07qzIi4(B@E zS=l(Jy4{wfB!_f=IoNnfp*P3d%kcqtu}7&aF@e|tes1YBf#98uEkS(_EQtW~w~`X+ zOyQBN9K6b)iwup<>xGZI&My65g;OU+Vz}>G7jwB~4eYsGXL~f5=}wl_kH=0X-8Iwi zk`Gcd!%l@R1j_8kpTcz)o6HsWMk`=h-OR^)qF_~JTP)f5WNtFeoh%{xCnyFhlY(OM zdUpx)6};Vd=ja`yew7x?lK{fN@k`}LT|i1AEtkh-(Vw@9u<|F)FqX5Yu{|}k^>c@u zLVKC|g)WqzZ6f#ep~{e<&K52Vg2g+`>e3(QzFbppMoMr8><#w{eDyLekId^MT!4K2PO zpTVf3>47Km@B2jTCGU-q%4Rsf{`j!|+2xdU{gWngUz(61S|ubknB|En$+8J<4{em8 zj+)!~J={|7@IyL%{uhz0MsEEW)OMA&_>RSt7k3L`! z4bE7qI_K;2{q#mXLP6{&@4w-km`U>r)SRR z0H~Z#iOu+i4bAwc79MGg1vEjr&10HY6)LMQ3h3f1y{TW)YbJ#enou>9Y#@pR8`$MY z_6K>cKSRW(o1JjwZU|jf-upT{oQTmmFH0J?i+TrVj&mj14o0DDN?yBoJP`_Y&ztHe zEWJKJBFEb$9lraqyP_H1@Svy){%$*Jsr$#dL=bED2s-tK|LLAdy}cQ?tP~$-lg%=@ zGcVwTbPCL&7Kcly|E_VEdFS^zr34EWNy$%UfC%%ss*_#(CS}B*wBwUO?b6Qzd_pZk zoXc{#v^V<-<8+H?7ffhy^h<5nio*MPT{@kyumxE{!?!TT%>t3a2D2 z0<%~~JHuDS%tguRA2?Qb?v2euAY&4osZo7XR6h)zbj&tX7-V-E`YmP1r-!1|{BT*E zuTmWdHTt~2cwpb^W>RhVteG?EC3&v?Wf9QGj4KJFy z>Rgm}=U&F?1wOddfm#vefoV!CL!ysprwg}pke@9dJ!v5rE$UtDGS z3rRdZy-in{o+@NZ@`UnrpBuPNBd)}*#UA2}Fogw*0tMP$6SKOJuK=f$2lY2RP4(fq24@(+$#QZ`qL`!vQIc4|DPJEoNaOR zRrTpQDJ;M1uyIPZj|8&&R%vMj(pu}19$j$Q(jjp9YIMP`IIoIf`#XT4zsYzAhm210hJrtl%FgxpwA`A_f`dZ$@Oxfwv`ah4JCgYywtuD7 z^U8IvxJ2&9=F5%&1PTNA@HhoN&(G~MB4w2__#OzbGUPFN#p8O`qgU~CV{Bj=^|GtT zfbGv;PDPKeYU(DJ1_6$!0OzUZ3rR;`gB`c?yUHR`U&GcNo}I(*%YJk@kf+ERyLhrJ z8^`8xZ9#gBq`tkpO6P0WU8<^Hh`auO1s_ z$%B1Ok$0I|)XI5Mc1bpb7Z783{Mhx;f} z7g)?bTYuhV_AvOS%$oiCgfb#qCah7*L$8D_-xYsxxvq)i*Ur|v?~86efQjNqC*E|? zg*-kSb9Q`nuUb?jvMto#8yc&Y*(yOMg0EVP-*MJ2o{QgEPni*5KJbG?=h+FsWNLPC z1N)NGwm_3e#ZVvL!5g3!@c=zXTe^bj0)aw>1v#KI#U!{C<9wmrXZQ7t=0$aMM_MIn z**>q;bv5U+^2_Jd>E~@X;b4yt`1<@ovjS})V?<5MBrDtou`zJaHWM!#9InaN9G-`k zA1DstAUz28)mjiAi083SWWOP9ssu@FK(H#juAARKI$Y)o4=@wXUo&82%RgES$8xsp z=pfR0U1dA?G2zyABPMN*xvyvyK6kQQNTzp~m;IHO49d_nrBkw%XpmMtagu~ArU;|b zt}^02K;F(k<4A$mT^kZ2KW#Jn7XQUB0jGI3K01|r>-2G?&*xz8Ii|eDoq3$@077dg z*{)GQvy(PFsp3+wB`=CNDv-x`1FT@p$AJ_#SZsSN0;971T3cV@|8H0!xuYDp<+S|s z*zJZ0@wgSkBtJ{RY1UUE#7cgY#~Os8$<%2$EzGi^b2~d3pm5DOlK*l=8xni32fXI5O~oWl z%;|lkfB}GS{&Td{IHAF-@#dFR->uHB6=p6;3;rc=U;819z~zZHkVuNm>fJyq*y~N1 z{87z|GPyMJl!L?=WmUa?DD97xCa!`s$2i%|STL@?=1wI5_0m*55&CX>Z0Ka=ECqht z0L5Fvk)$Ge;OB~#k|e9iIHkvNFPr~%|AwBxIEgy^xb$k@L=U<75YO2iDTWI`YveIZ%LcN*ZM0CV(`}I{ zhL0Y6R^Z|9(?#|*FxROXuj0dIaG-qskA$fV$l(SBSoj38c_ufCCTstatR_o$0$4WP z8UhFF=kv8@C+qJj*=W3%cKs?`eg_ILE5YzgMe2FVshdLT3GsxwSUY{$z2n`0%m#zo zDR0#pd;me=KsjEfGej3sPOz|hq9}_M)!#a`szL-0u#qrM!8_~pwZV<{eW$zL*J11j3r!MAr0(Bv=V7Cr zLp-dY^{aNDnO$KieBN?wOXzDF21`sa3Rhe!Jm{hR`}vfO!UYD{8aEt-dGpIHFJY$t z`4-#p>^s_nD;Ymdh2V2TMXGPf+>Li5OlQc)z+p|&Y&<|)tZeof)GPur%o(gSZ#66s zkuF&OWTm__5gxNX&Rulel5Y?psJ4v9TPhu zB4Av@9vmtowKOXT3^*a!wvySFu|O*i97o;IE-LAGE&}_YyY2gjoW)t?4t$LN>Y_H?!yS|OCS zyK`5p(m|X=h`VG)DvW{F^R!pQC>q$2phwQmaO#5jtx1=&&7+q7o7Oo2(tbUxNd z=>fN=kGZ~`h*J)2d7bU))JH`4AXQRvbknUKjJ6Mf5)+~z@|&f70{mueies3V1AIyW zF|Y_4+mFDzK%ls|GnM04@HDM#bi^ewl})ekfc(hsQ(gbBC!MQ&3$PcXGF$2qE_mX)r5f*uQ2OLl zo~T*#BY`ZCnMGK3zDxDx<@(qSu`&1XMk&d$HciGM(?qN+@R`1h8h-;X{dL!C&*1x~ zDw7gnyEsrLsoKb=;gkpSz|m<;7$VNg=>&XWV2Pu2-gz`j=go-&2nOvbu2Tow*Dyiv z+Jhq9sfr?-dHg#0Yw#Kl@(-;1ED}RzIns_vxrE9CrHk%`_m^o6uaREE+v7G5Hv;V6 z=g;2^!E|R&>e2b@IS6#)EB}VCIUoQEN<{0BR#wu`_8((CB3yTZntnPO57?tb(Q0<> zz(~ofJA%=-kZWLJCZ@UHom+`9`ISGh!N`0fw-2-J>b*M)AS_j{MDfTGW{$6U39!Qk78nKDYA%L5a~O=y*WuoZC#s2W_(&j%>b2#J0K-a>nW=R z?HO6fcNn^jS;{bnxs5FiySruTYwkgQr_zE6vnrqplx|6cDj5iaraBFYUhEmoGTvZ) zJ4Dn2QIK&1<(LK545dnESK(crtafvwtcYsvs?T3$p8EOHjLe==kCl_?bitup*zv7R zcwLCHbJ050Mh-7oU9^Fuw+I1!gN*TToJXhElz>=7kBXfK1lSrjlwn3^e zrwSrIGGE4y)*0bl^A0!B*(fF8MSlS#VY>BLvvg1s7a@~-ogwY)@C!PQd2pT^4XX&4 zuq6--5JeR&OEPq8^r(raA?^arsr{%zYNsOlmV87?T$fyd_Mj)We6dthEJpv_sg#}+ zZq{n@Kr>jOFKQn0%jeVu@2PKv-0apAgz?mgNs;*|b0;V^M`sV!bo#5L#24?Rs$XJr zfI1%JNLD$buGmVj#a8a8xq|w0>E0n4CBrL#*)kVC?yD+=F8y%~f;O8$78G^0*#m^X zx*wZw!1fgX|DEWHhtHBhrkXm#{y{RGJ4~}tCgHV8hcm6&jjw%rhGsqC5l)*sdq+9a z$MQp~K{lNeAz6L60H&r;yAXytT{zQV?_T}2h_uN?h1818S#n%9qLSFZf|^3E3;X~M z!kOg;t!mniKD;E4KOZ$H?R;up8txN7{us6T*L)j=*VnQlB=#Z|2)1X#upeK#>jiZ&)?8?A5HW!m>>wfd-VVgF9t<4wDKMr%U zLUsrs9gV7t03=~c`AZ1ehxv0Hz8xr|T6WgNpga?_YTI~+f>dFYLYR|g zQ{?yArl8#Jx$TDaiFS~3R%jIh;TN0ST~rO}==QV#JX2N<8{j%h>S8^oBHSZ}=OH*k z1_tW_K4zna7y4kO(v3-CT&Y$XfgG&SxrIl#Lk`n7lT2*sx;iwTrj@iukt!>dmu`eF zT-uzc_pUm>48XKECsm3lJWrL?<1QG4KwIuwa7hbK$qQTo0nS&_o&KBn?ueIHT$3`D zwm7l^Z400uPjfSM4Qp&}>m*f<&tOrO{Rb;H$M931TAuDOOKuR5iyFI=7v;{wTjphn zVUnMQc@^!T#eZII_b@Az@BpJ_Kz$hXo#3a>+L5+3lF*osjp;-ToEX%4DU;$JCNy{H z3I9%*QWw!VT;`lc?8Jm|fy@mtL(4_Y!^~(PD=Vh5mD+Y#Hb@rAIN%#XuivY)W8WEG zLFdY5O@Hj?&f)1w#l%!e7H|`4d`C-*KaOaLObFAcKbKIL^F-DNb1pbVy@&lYQKt`9L1+st<*I8nzL`W#21xvprap|%_s})4WYsl0_8JayT)N;olCo0Le%wy0P@XJP%BA=~ z9X@g5P>4{E9(@$9*9>l}FI`M*)2!H8FW6+wFA16IsxR_yL%m-|LCpcHcnL1XT{`5N z_-Pb$M#S0F?eIo(8vlSNq5`rtRe%|4yuvvX(s(GU{_)Q=x<^Dh|u*#It_>p=e&KYgN^X|Mz2Y)9_R;vLn2 z!QM@EY?s)0$0o%IHQ6qxXyGy|DTr;|TdXNp+ildu&KyrTf0mk>KHO)mCDOC@L}say z@;FDEKUWd{vjr<)w4jrOz}betidC-5F28mi1pC@z3e>-e(H&ONq=4q7h=SeO0F==R zEjhsXtjOOr!@thria!4(;8@WOL>x>igR52o!M54sO%I~l?`#z3cJjM9L-SY zdJ2cb88L(vyF$KZ&>$k((#T~a#y|({($h?v50pFpzuloHoj!xlmL3ehQ1c5B4}x|0 ziI^UENT`ULBSw$XmWGv5b5BW|*y-1F{O>WM7G0ALI!8C!pN@~XPaz&ik&vNfgVF8J z187<4!@3KPA#62!uFHOj{dxmXpBoMtD*u|ayP5aR=n_DB#<}av_w~A zvnW-B8P&eNc%Qf3G^GmcJmO}%${Z6#XOg3ao2V3WO})reqxkMpC~@GrzmIrDjx%wg zNl(DrPoxELthp+Z|BU)=UMGu0{Y3O+woGNl5+Bz_$ zSZy~^qp4uBd~N~~2*c!YVfCj4Su4^RUG6qH{keU`Ks<`CL5m4%X7xCX24QT z^jG7|#;bMkY$?=cQ!X?of6x=45pKW9w7Wv;TNwdvHLKX5ql~HPBT5c05&xYz=B0wE zjMnrn?o|37(Q^c=&zD#Mo%Q{<%i5S_aV)1Av45gowjw}y= z_`z0K|5wt<)$VF>8f5~R6pOA)jl9H#P?Jr1}I z4MuRrIay=)h@Gj1khkzP6yxV?0c<+-qro(bACv^MPMwS9Jxo2{OeXVX>vXzflJ_og zLGr^vvi{7w;bqM>P`;xJI-@N6P5kLL!o;X63d$8krHgx_5saMX(*MLyycuLuD`YhH zkwGH<9t5ExA{FKnos(mthI0mf{qQE!9TRu%?`a>$VDnOQGZ~<{!bmDXPSH*NSLZD@ zB|!#iPlKIiwe8>+F+QI!&yx_nN95lM7^V?@4%#$gZ~7APxZE#$s6h!t%w z&eU{?3a>H2M>tTBnNIWo|33i00P+r0J!0FcvNyS7chWvv_$IyK+#+%#7~~Si$|oU$ zK(fabC{I^Z$8|ItRJAVxa=0mk#_+7J#HXgiUrQXPkacY_J=Z-i0l<9oY=U9b&Aje< zVU%CBdGXHvx+(Q0#pyy7cInZtn@GdYz8yv0d^)}?ei7VT!=NGpUL$8yB!3*^b#!zm}q|M{!B8-)OV)oVjJOikgUgL76)M3#bF9aU3Won zunUR|6RI>?{L|Ha|Gz%TB>i?-98&FTmj5oVF0iJCvkC$1`iuyWhNsi4=$&4bd^{bR z7{nsn^$6Gqt_W*Dq|kzBh{&5lu=eQ3@G6NJ&LjU}4=e$PG0kR}Dx~TNdVN_-$ak!6 zj0f8ai@*o+p^SPMu@N=0TMOq{(DsY%4}Or->Py5aCUEnA%ScNf`ghe6wedadhM6$F zUm5U>c-Ml*TMdziQn&?>OFD0pNdAxT~%ms>A@`mI*u zaDo)aj`=arWMJccXU3bIcN68CpWz^O+gevA-zh)c9A(3x^y$k3l zEaliEwJ1lO6@JgwT$i->?MO`?>>t9}K*)*&5AFRVW7*~51SpQM%P5>3E|-#<-{!U1 zovOZ?c)kGLVW=IZYs%m^(sd19jnrA3$^^r+o{(}8u4a!>Xr0RW;^@=`O8Tp?RBfh! zQjru}rdKRY88!X_2NF@DT{7b7(<79Cl9K@=N$-lcx5*P$Pcnd>EKjrJjj~x(>-V4i zj*s3(*-4yO;hT;JJZvBI5!0$FHl2f&*ec(N|s#i9mpDGf;waI~(!^R!;> zoE5KcvHj1OkDMm{zccO3qrS@|=O}_EQmuJG!@x5s2V17|f`tgq} zZvAI^yZY)?Qu0#)PjFmORMOaHx8f^#BHLYSSV?wR3x+tnju+rJ*nOriB;13JOj}3_ zpZ&Eut(7`7aMNvs*{`IPzITv~zvCt6gS~}e;MsQj!%(B8I9nomPtcKh-U*a}JU|GdD`-({UhH0^Q_n=sQb%qr2c+ z>2kkK6*}w!ytm{w^t>=Qh=k8cdt%)F;zS^q&}B<)A9PzEC;xO)3^BFF^X3$!ca9Y) zPSM#o3&CPfKqUU|0Ci^AZoOD*DOvgd^4}zpJCd0M5qG?aMUOV3m>tys(mdj|zG&mV zckoF-!yj~HBHSPYKyrU#(x>35J)u{+At*hBzp#JWV+~S~kn>``X#EU6MpG-#AKaPtqp;ff{S^XYimyM3yR{QPbmtdCiYo{Mi0sLzQ(cL1VLmymVy&&CP@=0W1RFIMlbN*@A zyTYQR>@wC;^aX9@uDr!-xu%@n6My<489&nU>ylr|dE4c^{Sc&35o=;RU0Pu$qk&{h zWGD<9 zQ9Q05nuEIt5V^ONGp5$M#cm(4&%cH)MYAHqVbg-#*!(kBZgjiW(I79M?ZK-AJkhf2 z&4k6+m3bWq*``{iZSL+?&j20GZ=)=+{?B%=Wdk3mx6J0dPw(uXenzk477_O@dtp%T zjaVCf_6=$GH-^p*nA^(9KapDpq20oKiulx!mb4;?23`59i`KS+l(vyS+$Ws(J(BQ8 z2~^~ly1Nz-1Q(B@o|LAw8K*H>&w;unuf9Nu)-c{n7`B6y>uVJJ#b+a}==*apZ}{vH1s11#QSF5<^~hIU-+8*()<8%n~Q z1yAU^74)M9Yjs`f+;2ts+u%IK>5yxGz|&hEo!_i{I1~}`_0n>{PUCir`pxao(^K*g zGRlW#HB$A$(6wroVP6wiBYc*NqY4wOOo2*OH0wOhHHSRAl3^bL5>@=yve-b4Fc2uo zVO5Tkqv*--=?W0vL26S7JGLeK5}qyCP?4AWbVJ;vYG1hTH!c#fS|48k1jg5IU4%&l zaG2O6MHa`(watEa?5>=2cK$_JEe}LuV;v-2uW2d9p zVFs;@7Dc%)KZ&b1c3Zp5Hlbr&d&a}{NSkpOJtH2vPM67 z3RH)bKWq4ZB527eToaoeH= z6GEAwJ@+;*7`dznA$nS6))$v2) zS#m$d7w(qpA+-zVf|{@@%w>JJ+}7M)PUOSzI8nYHJt6DtB(dOF@JL*~POlfqiZcb? z$o!X;G)ez~N$x^!Fw>w%R63ckHoH3T$%1!9LskS}lMhstayAO;1zUD1DJvYabIJnB z;O2DS^V(QkNYxfsxT+ZqD2F9CXmZ{m4by&9LE4y{7j~@j51-3VXyv_S&^xr%KYbIWm?Xr)6Bb1N0YylSFUCo9q3mq=K>Fs)V z2SMWtY_ToOwo3cu$@~|_rE!qwScN`zWzZ8R2(skq!X2?_B{51=c*`)IU>KIW!r`lxbk?zYZmkXwZ^;*$EHLcA!x-*9x zDZCXnAf(XCvkTS0Gv0cWYP^Yob3x2TdZjh-I;?PuCctS4(#fINhnMATTqy(-gx>fsPhcb_&#u<2mM;<90>Cl80R67`=tq1&Ktbee% z`#*U|a~0OhhMIlM^yrgLiBWWdm1!7d=o~^;{NZd>dRr@4;dbJ`GOL@W(P+ zac3#9CXk)e=HkXGIGGC#D4QrxQn?-2zi=*y+SdX`E+7lID2Mg*7fd&@VtZ?3<$ar=W)D~NPkZ~H1uCLI{04^Ur z<%bScQutDz2a#pr%>T=a)ou z!y}$d11Kh`xKm)a@qZtbBN4n&LXWusK6#Zsgi@GDWd!#WtHo&x?G4w9FL_0t8g-$V z2*9H>C*7Pq)?5cv%i%gzYWT=LCsj9(mJ6R1nv=kkChLgCk(zi_#-UR0fS(7?z*~gw zP96yJP*OUBD&&p#9q~E9&d}ex;2iHIhdxv4XNZ8D=06`ae6M5wCdgDRhYxu)P7?@M zpdk!e2;w<=TxFtD=hE9!-sVp3@ZAsRk(n_&BSn+H?zcHRI3}9G{oM4xD{uc$zqp% zXDhL1BL05{lNd|qaOSQFzu_r!J7yK3XArqdrJ&A1|Z8(?m=^4huJix zmY5@3p$@>`YMmgX`(|9Np)O0wp`RzthIyx6arDBqR$hVjq!(xI8(be2C}C03-r=?1 zyB$vhCLQ(kipxr8b&cnlJjVG8+zdNT>^5>WA*^D8t%}D-PG#Ur4%hw#Y;IV#oI~72 z)Ay7#6S?fTvU5QmJm$p880UgfY40!816hk!Gf)G%I$I?`vrCm361Q#Il`6gY=Ty<6 zR+5;c11>K7-gIlND!f50)4%DrTECGbEc+ZNuL*wzHFq3hY9sp@Eo{X7x4*SlqnHh( zOj`fh`_Rj=f)+!_jZ}QMWQ@_B-o!xqP2Gkpo?;G z8oS9(#>te3zX$C}c_bGW5-n?ETYXCcp6bl!C2dhE+*pkMzP^Q|&54ct zwKmt!Thu5=;2!@+r_4y>tCy|;_7X^`I?mZyw(c#XC{=TM9zf%Jts{VKDWtJNg}J9? zd5%*aTYGy)8rVEL;)8dif-Z4!&Ydw_mPmfA1A=f%ZA<6>S?LJQ3bNYA_}H?f!`0Bd z%MucH+vbc5pVB&NoBL@uN@wA#zAGZwv2yu03YED$u_j&<0}^?DxGT3=O;lv> zs0W>!A@@N4-baeSX?Dj$_^l~F^a=`?>u*tW?WN$2i=jk&|49KQqz#ANnoWPbN?pj8 zEI%7@6%Z-8H#lbknVtInqfc=p;NGs?#{%A@dXrqdV5Oh?aPoGNK;pSYSNT}qWV~1y z738bGF|*p?QMaNP65TZYXW&sjx`FnES!2NHv2~v+Ad`-5&P`>fRr(O+x$Kav(E%mS z+rg0%J#RF|J8Z?MfqtQq1kV;!x+{cSu;Kb`s7&~YVztOBmM2PR*<`qzM(c$MPrp;YrT|Dvta#(GM$ zZTDVW6rmvPlmAv!8ySmCN@`Q(^iy0f5`O)hlGugcxFUKp362%kloNMlDVbvfaYcLO zOR$MNWNqe74*nnUx6Gomk|M8vhcX)zLQROxX5YkO;%-4X4W&+SsA~`DcAS^E-R}*_ z5XQ|O8BgqS_CDhon!W=`{+|RbT;a5beNgp-1=VZn_=Oj z+q2aWO+8297KcFQ_5HU2kO?kC5?rAwKpym>dmXd*t63RTewVGpjb6RFUxdqY7;R~} zU_eNNW#@}8fohBY$}9_~NG-x&f5#!54Mu>dNv!R=%yzl6|BozFAc2Wj2aJfbZ5lBE1+XqZ@DxqbIPX#gh7nvM>|K&{ zrt(+NjWh<_V~!lF5&Pi&tQ^}lL4hZ(WU}8Wd9+*oD!1BgS*+C*c45*glffbjaO+B(iCZo+T%-$s<)~#X-soJ(sceoy%g?e*Sej{C?O(b z8WDaNXOv~NJdXs!cB91%Z1$kWH{~!NsVw$|hQ?)o(7N>6n!C14LD59J&~lM&G*tk7 zCE!G*{2^GzR}otCqh8{qKdfO3)D{6;k|ZY?D++__>6ps>x&Vpvc!Q@|rngi=SgAK% zBgoh@3`>U1W!_Nys5~I{w3$WAOPid(kawb-x?H*KT`VkzF$Jk6Q*pq@j@i7Q5|T!_ zHUI;ndr+m6r#DX+OALiHD5Ry6+faKRz3CHSe&egI5b$mnf0%I09Zz<4k^wNAqFa$0NtP*2=THU4~M@;>~d48&#m}Dd& zO<&W?Lv*f47eOWK(w+{1Nm?a}jz=qGrXCoAf@ax$1^s&cBc7v~-d6o;N#` z#>)*(5#`(4tI_`ndjHdC?bkYx09a+D%0O7mZ@gybk!gk-_}feba+ZY)w~F|qUu0Y- zk4rgpP?#VPBi@2QgSn+n!|n%!cZoaJAEkNWHP;{;+AP{84zT2#hHq`0sdZCJ!K;9a zD)3;d=dw^^mFjFxao~R=wMF9wlq!c%g1kN zdtjV}4%&ZI=lYNmQWDCFcBqAu+*|;D?~)}tvC{ApeKOYc()v7JfSB*kDqF<~eC1g= zr$cmi%%@+EKGZeRiei!~^+!(r4O;cjSd}RXa^UJ@p2Zn9fnfpx4VWni#D`1b+49`k zuaIh+fk6ToIQ4zvlEITPN9<*xW;8ZP9LJvWBHILiZv(s8!dg!G14Y4h)rMKae;036 z4kI2DB2ou}y;Jrj4lyolzF3=jQs>8%_`SnVb@`nW=n;=xZ=EnrknvSyF|MLYjf6bg zJ^{BGR^Y|=(&|wkEHx0k?O~j`au2im(UD|U5UXW{-Aq+aE%1v#@Vw+QvL^RS(KT*f zB7Jo%XliFRs^rTZgG++1n`cC6Wt}w)e$!PvGQJkbrzomcmvO4PYBXoc+nOa~L% zSyQCLJ9NfyzQA9ZV^1pu#uk}~=GC+Fu9slMGwOnL42-%2jpexhm1aWyjiGfB{n;J+4%!+tgzNcn#au9B(A|_&@E}yHu=6f)T*y?$@%}W3!C=NZ;)k3Sd zuUZKq&5c1{D!vceBpMlfK30czQs~cdjVNA)~oblP3}|N2~@XVX5!LyPVQAcw6%CE;ifaP z@>0J!qJ4x#&==rOiM}(CbIi^LNSy3-uaHF&%?RrEc8J{|JrtXA+ih%5+O?9e$e^%b zA8t3ktB)s0Kp59>-UzH!FY;O6=Md!bobQuAcw#AK+aEZZ^_kclZ#GQ_^(@v@cxFS3 z-)ET-4zV%4Ge(gX+^I*UG-;) zaH1`S);WKJ$g>wjcQFkQ_T(*14It%NS})Fxbo&7Dko&877<~w&#awA0C|_-vR61&f z0#D%>n-V@^&hG=k6P;rgedL!TNQYr{;Y^hRjzYnIvCvkw5xmwNS97k0gt)4l_%PYt zURy`CXL)nMnEHcldW>zQw@p@zYUsTXQ@ESxRGagOtukvKOu^o8i}{b~i;-)2UO38&PlR#RAw!WbCfg%?Oa^|4-aKHPV2`9wfTIz*;1jsKd#QJUtXMzTWP zjkk>)DXTWHq!`K2IWTsYHnkz4GTAslaX-*;aSASBx&(5bg=ifJ)Q|%m`{u5#vniPt zS8hdJQZ~fIr7L#^id{CpPHUtFG6(E|9qBr7H+e=R9N<|O2#BD}P+N#g&O>15P)TWY z)o4mQ4<5CWhsrn0(2@HVfRndIu^0oa zMOUo<0x>4|i=Kcj?$a54WCJ{ieeFZ+e2UVj%KWu$as2rvzUAoCd);2mQ_rw((Yse( zR2q?wTDM88G46Tr2WKukMx4!&4B+!Fj~=C8e~j&M1n*j5?BkZ%B&)YO@$WRfd73KR zzzrmco~k!pE_fT4>B@m7G2u-ExW%ZDrS%s@HWwuB~w>?%v-xOO7j~U(h{QlJr_YRKO#DZ#^3Y5BtV_x znkAu%*dw`(j8i=kpNYJ@Xw47e?8_UQR>y0(Lno~eU%IoaN-&(~$|D1~mVN4Gz>k&j=D{5ZtiPQV=ddXa7O;kg&(yXSAAqFhvvq7{7(H99)QEM( zqFh|X-6a@`QL+;!QKUd(PYEryJ$6!=Lfh4>^8vwNW^gl ze7mA!i);{3>@Wqj4<6MV4VHl1Gn{Fsem0u%F>^f()P|$(b5h_6k!_HU;wEEFQ~bB5 z+V#o~a(1>nxDK3Sf`kQ@vmXG5G<)j{S7X=KtAoKF_X@tJ{++rA#l{Ow_lfK_rxtDO z85~3@GHWuPgplomEN7S`(_gbyY%q$GjA89C!!Ab>bjk3aSc^~adZTQ_m)(`R7}d7m z-efI9oPx_2GuNx9+bI-pk#9}}ESe*6^6d!vLg&}^W$H)1e7JjIHysdpVN_7WM2KB2 z{L=*vtPND?j82p=;USNSJ%;%)mV&@@?E|t2OLtG)j0u30-DGJS+oMb%T~Ngr^SK!l zNYdGU)G}v|&%g0ST<#V?!MCkZ4hMo-Xv zI5h-P=8rO?o003-7F4wL)uo;x<&lIQ=YWumV#4{Br_$NIRX-$`$`dt+11dFT!wjy> z$Y=o?=zJ78Ygrnet}PlywmEifQgW-*ponb$u?Rvc`G=m96?{g z^MKT}*rp{lP##-oP5lrbbC+u;7h2fqCKr-fno16VxG2WP7g*6`R?57E^tZS%&y zT2)G$O!((`eAQSd9MtbGyW_$uUP=R2Z*Ebhb8pF7Or zGg&g*CQW`}v-G1Gmw=7(9jAb+=cWWk0lDTV<=@Q={(bVD_vv(>hEAj|42Ng}Jn4bL z?6-CYE*1skb*1P=6@L3fQM^TM@|Q(YdnnSO!!Q$AF4pu|>+Tz!z2~d%S4kxkcMFKb zx9nOXLU8`gL`*?M?IW2`dcbYGwyY|&p0jWNCFeO>+&`B)uBcD%Efqu_JhKdh@Eeq( ztDK7GsC@OWxp$>6a>{4qpixD9;YFxkb(9YxdGj9_LiT%@yESa!m`};$Dy+EW?FV=r z)Vjqzccf78 z6qc6@rn-|Ug5h{1L@lqKkvK0`_WmpK6?T9oWU2q*L)W5-YM0BWb9f=2Tevri9{9GX z8S-0>Mkks?V{PSss={|6>T& zBv8#1Ez-p-nOTk4sFOb(?FmnkbUvH5XBZYs~;??**ya9xD*#rp8!!TC2umgG3pQk~VezFb^Dsa4l$S&5-s`DhS9KBgI#5s@=de}881(iVR z;=K}J)cZfbS?p^dSp+@6vTLA8*5W2~Gv|7+j2ZK8tI-+r3pr>bG7x(~m#&#qU2y|Q zOZ7+`eNTIe1Evo1uF=R_CTN2~n}yo#Z0JM`l5|lK zE(^#};WeyE^nyE8Z3kHn@^beU=PQg$_ix8;vhO1yXfZDnbAxm&d)~JTd3iGocl3<= zc4RJAhOxq9f(9|00$49oE;%kuh*)QsG`Uz382UC7p?Y??$^Up3g4C9~%uQ}Ua? zbM7yjM!RSBev4q(e?)Cq2kV**J8I1iRVO0SgI;*XHIugGV_#uys4*wdR`U!!{Ar8i z>KRgKKyGmXa3$W>kqkf-a7}y*3H!iV{BMy_*5uu+R&IYh@;hJ9KQ2KWWtiKFSq$%0 zogNlRb7N|p`|<{*+;VjI4piBoxd9493NW8{^WFNgOx=nheg1T_ne8_w&{@P}kV^$V zzdRLSo=>7hW7`e5x+OK*K0U$CS8X2*o8&W`f29dZ-B1JczW@2d${M9*rHQx}Ww zyj}1dNJP&73;semyb38nczqiLt47vhvm`)q6G-9Hh|$o^vwh243o0j*fbdTEg_%;D z6-MGRE<5#x`X$v(+&#El6g&cP*)@(}XdW@w*Ac3JO+wK5h{urn6{O} z6))gEQTC$FSFcIT3!2;o9?`;Lh1T9X69fZxV;|D3s&l|g*+PoJmyvKY9qvjCWqxT) zWr>H%1t{p5SgWKqwmdkISE-0}G|}kcl+DU8VmN5ZI?2#XFv(QcXWYZh#yX>QVvjRo z5G(oSnNQzVMGWbgc^24N(sq*^^r+uMBx*=i#m`0Dn%$^S17gv3;YO2u93-QK~dggfMo^aA@AEJ(w&%FpY zpOrV=m5580j!Z<@(t0(;#Yk&>3;v@N+8A`4X2|3LrBR(P@&NSo>(u2jQr_seM;XX{ z6Xkh{WXnd*=AkmmJKHX$HATJ0a!3PRAYVDitgv!nmCZ%T)eV)V_G0y6gi>o8A}pP+ zj6mitM0dLy*y6(V*OVUX#k&7o&PHJv3l-EXBmpwYn9mj^VlpBNs>BC3sNpnbnh^80 z`3`Wj&c&a@;XeJ0G(Zm+<)>uy6XqKWOI#HQBsI%wGd*#>?BH<1^o9LZE`YEIwr#+j zX2(2m;Ti78Y_Z=eO->vUtn&{lqc*H~WI)3f__$)ci*_^0 zh5i%eu6H3G9Z}Hx3avT)@zqxkqsFEJ#?JnB(-G9C*1UAm-9y9sTiYqR`EmaWaK`8~ z+SK8C#to?Uz_sF5a=NCCU!dx;PH*Pm)fO9!gP!J-_`R&r3*xBOoO~NK_dS6_SvrAz zyFw%55GGGbkYWAH-)EOz)B2SN_fnQ1*Iny&ObTZnsng|Rcsl@Fj@avBdfLSN)Rcy@r*LA* zM6z+@ovo-8mvt^#^wh!eaDFz?o@KlpQ#HV5M7#LSlU&l`om(BCg{Mm~R=PPTF(3XV z(wubhKOOqQLCeyw$O2M?32GAfGNmN@s#HKv{C>fF>t>Tl-(@^I8O7Myb}rvx!M1=3 zmPMwF*5clcvc%Mje-I*cbnH#*5-7lhC2-{9)eVuV22N-I+NAbnn zKv&9i;&a`K91s?Z__e&QLYNAUc_N)cdAKHFMby_0mnEakAJ4_dpS+SB5NW^;F&{0b zneK;EdA9G$n-PW|-sYBDef&d&Q!)~UW_XxD%5r~+A%XSUJsOfh_J?jN@BLMLo0h}_ z=-KUYXfRy>vmnWZ71n-=Q~_#M;Yw(ek;um>qLuC%ixH%kF4MH(aPeyYWTpyd71XF4 zUd_|yqJQB!k2pvz8%@5LS9L04m7_V3h1W3&EjawgPxYDI-4LI{)e9GjzA?XkJ#k@V zS8w=L298uDI_J-$P;8Yq0n^( zN~5o@BiA;;elk3WL}o4>Q|9X@)C3)StEV$rbE`kM?>$vH=^r2_eJw{HceZ_=jIhlN zQXnqUqEGjF!0@8T_1O3QJOSa_<=92>(ER0$e)vY{qMqa8^I%eP$pv_Vit+0_Gdsqh zkhcb}%)-^{(@8Ejr{E1Q4&vt|QrkmjA+DvpFx}6*d6dUnN_{D+5LK!7tJmf9u+~Zj zgt0ik%tNS=$E-uMwCl9cJ9B%%vti=;Q~T&tZp$tt=1hlx>fbOsBj?d|c*u%e{f!xf z&mJtEU~HHWle)m*!U5qR1f<|VCxlirS^x`5ts{{n^U|;Zz=|ailx+pRY2{Xs!Ik8k zLWlaLVa=kXJ8fRlC4#aVWI>5X_Q>1#sMp7tt4Y=I67q_7eo{P^9iLwsFp*3VR)YXt zLtx13_HBcd(e>7_&QtXw{KU?ot^g=gNoyUXXEg&KYUu`*P}t9dFLM1F2^Dx{+_TSj z46J~I$q9Ir7%AvQhkL*J9i3uM0l``HUymc895QOZY}Kv=-JETEkg`DF-Zz_n@PiyC zLRF}=bLBDXFhAl!v4rkCFD_jFU-7pdv|H=^bDzKhhw(rjc>T}NFj*)G@)f5wgZO~S z^OaouH$2x6r89vSfAUVkbaAO^;JN0u>iuGFJUG8U$*BN{)BP>^rMnMNYG515`9+^|<^!60dU$B3N@&P?MeIq_Y2e zni!!5`b1PFw?;M@@A7Mbrx z+eW6FdR!+;rYQm-oBJnyrrgz-X4DHco@%0j9mXI9MyqIt@R~BaJOEm0fx~o@HgtB{ ztRvwAef#4kxeToPj0acpKflzFA4M#Jg%>8J6(M;r9RH1<2Lh|#H~YzI6z#kz?$t}4 zZ2mD>#hiIo=k|y%PWY7ctiy2uLva}<8U|o>(NDaEc&JY|6mmOmTqW_iO&>FAj9k60 zM2%Oj8*V*>CbtKuiy@;eAW>#MTDv{VD-sQ>Lmh}G_DuwwGcR+Cb%_eOo4{@!J0y<( z*sR`+?AxLr0rr#nbyKjW!xUX~mTvFw6DaWToDN>b-TSjM!T(!A?dcyxk^{%1lRD#& zRs<1t{}w!z19*u)foCztOfTNd|3$)pq&Ed=mOAldo`e?t!0X$iH10`d-NcWd;2J8> z_h0&V`~dD1bIq@Gpo22gpQMM**TvN!q;cs{(fj1&PxKS4uLDqJ9y4arqP0NeXgQ^I7#JM?2pfY&&+AjEK;tw@ z_m&Zi=_e8T@%Vfqx%MuL=d?-9o(_yd_kpQwZ1cWi-fz7;8qhq*#}rhuXTfxG@;I~+ zL0V4>t?@NgMQWqER6sN=G@ynx6MI?4Pgbio1?n0&j!=tR(Z@ggDTSX^xzg$Ou{>|J z+BCZ6q(V83xQMgd7lb+2!Wo_>Wav(XdYZxtDZh(vYOulxVh%l(|HyI!Kzag6=9u|( z9zw?U?vBF@=A0}OF(~hN6F;bvJ-F1eom1sHQ%0q;!#zK~ z=kPBzbb(a~Qv#38+W$oNg$N34RM5(RngPR%!4!*2vhz>lSama*-$->z;N+7y%YtLR zBFD1$SxHG27H!W?qQ$a5bN>6$+=?H13sni{7N0<#6BTHYi63_@o>?} z_*uk3@CKxc9y@C1*R{O(5U*^>f>&@WNu~ZU1D3$UxCHuxxE>%2Z_4l)s8IHJr08nemCT!-ix9a{#F1Qg6{cDyNI(EAJ4;dYlXb&J1YN=2Z)LqJ1Cfcp#5t8k_IdWMwGRZVgh=upx3 znApY-7Q?@4^Pv%m)(h%k>PU4n1f+MuS0QY9?6!2F7CMEA?FF;{KH#ic8PY|GA#A4_ z7h0EOFdtD^#TI+V{U2=3{16sOA#rP;z^cnw<9|N4t!Zdh*r&H+RdeplyzbKJX&09F zD@(JAoKFq^2_GR+bnMh`mMj~~(&87I@w1GJJ4H>hy)1zRJ>%oIw& z&FAdXnPCvobXHXQb@gAiSfOTWS+(IDS^?K&FXmKC>k6}i*fbMnV6#@M;Iepw)-*&f zfNNO1DrpoLrhG~j0^z$*&alZNXu-Lk&XLAd?(@*_dBvI3QnuT-V!sQ(rm1aj1_v%9 zJggB~`O3+@SKWFxry<<7`N{l)FmFNul4k0GBSF&qHm$3LpN06U*$ExB)LDSH+ z^3xVU6W4b+H9A`M+i%Nh8_o!8S6Tp2u&V=+B&iHe2{x)xUGuXKjqjh2p0^Xf0s%@h z-@;O3VoJnwaM0Fw0jMwiWrKWQW8%CQ%CL+gOwN;^MfUQRo}EAFW45H9k_vB!Ku+0o z|Ckltm~-Tjo~+X^w>DB*@&|eVA-Zel0W_+w=y)aT2k$(4A+s`kb}(?9yJqW9WNvsi zYA2;`E&z)&+?fwW5{&(@KZW>h=HEC7yKN6|5ud>bdS=_$({lbr{mFt%hDa@t!RUIK z=L}9p{Pcs) z&+-FMXy#J8@DYp`#BL+QztuvT@J8E@fQ>uX&JE>ZM2M7n29_C&l5GCNFWJ`Gv?5@( zHES8Q%GgOGSqj|VOEgtQQx$euTzg1w;;FM~$1;s_&~%fZi--81%J4Ll+&Jk+8&~#R zBlD2L$i-(NWexNnAyp$T!e1%D@6q{_Wn+@zeauPC4IEUN3;^R{m>3oZ z_GMlhtxchL+VlVjz1ZA)qf)=-L)VD`@|!(@+R1XC3++-#uLeZE2KocHpx#X*xqyup z@e_&tP0rBzTrPesC`icyy0V4_dwF0}TK_j+L#=O~oz&o1v>usvbw6h~L(p?zm5T8m z1T^8cP|>!h8_AX7w1c;Vo*{`WjaQSWbOB#Y8g#_)ME=ixp3=_cuf0vi zL8uz`Ef|?4a=+DxHtAVtBSRaCzHTsfdx~af6el4{@VBel`43168|~9BXoKyzVCP|? zT-#MUC-^u+!@VP``QE@aajl;TJ47YyC-UO&y@R9)PQ=3juBv_Iy7n6f))U|x=$OS8 zc6u~^%F8*HRu+-od0W7nBU7m$7}_84e*+dQ4?NVOL!~Xm#D&f zENV%nbU;OE)*Yz}N~K6M)!|TvIQ09Pra)1OUau`jV-)p>4FGt?y4wYaJeNc>UnU32 z*MX`G%^J$+{5qcJIT+@| zgubm8{Cp%;XCeB_4W-S?%f<>Gp(qxd5k!sJg$lmlSgm&ue;KSo($a{RH#D7^A$laR z#bjAV7R+ek))ey2HjKqrjHFv2y;!mbPqJ(^# z^<;WF6tA?zAr-f2P>2jtNULd%5G;Rw&P#=C>d^w&w+ql$Ou$gz*)0*ZmtBJW%;h~+ zZ)SDZrn<$kr%-?@#=>hV(KCzg*)A!$ludS$#~F>pRwS-lv(rAVpPghmX|4!W8gza< zusU64#-cwQFd3}(@wU4lHenKDidrkPn!QEk@J;2- zU)(@n8Ga2uW`OjkOTXB25PbeetIQrz#_RI`Fd(>X3sye z^&QG_&V^g^{)sm%DV0yzt%9V;?Xi03#QK}wc)n|8I2|?-u1tPOBUJ?d2-w#K_I1qY zw@CfXq zRb?;T7(r-^cb){T{daZUFuW!O?_aq;wR4X-e2hL(o-&0{{Oob1#jwh=+yK}T&d$LI z-p1OK%Klu=fR32iJ!BalQkm+iw6mFf#CB82m0JS9iqd-$%*dG{NGKjPkdHd}nmR|V zf4iscLjR5VfKwLQ!im@MiC7;shCm5HhXg$rAmHT)q7i72d$?v6`h3YE zegvHUWS%vIgR0Cfjy~MW8AUPt=-*!ywy#xYgNUs$oD!?vwdGIvF*2eBtokDr6pZms zXl^nr`k$yHbHKZzg;3{Ub)DlYHXuK$3H!bWLY<;y{`woDH$yI?bD_AlKbozuMFRcs zI`dT9r--mkxdu$k{c(k=QsIr`%{(I3WE2lU6)MF}Dq~1cL6WuJLDYBohpdP@h#<^z zTVw7*sc_DSGpq-!&-V8`^i6j?_rNP;5w?BbwB1rR;wAU1#EKeR?OSrlB<&9J$~hvh zGkrh)mY`#?%2lDLHGXbWha5u(K{*@%|33i0+nrR5ulyH)fjFGryuK|;?D`W$T<(4A z52PZOWT{R#^T6|>s(sP(PMnRf5i_C*nicakJdNv#Ye= zGp_`X3%tE-7G*QYEcwmK#SG5caF9pT!QYvX4priF$4N|TZwCRL8#<{KK=qHe^Mpn5 z>`ggu=WvL4L<8(pfUEcyFHEtW>2nBDr9dU51q#?7(fTtL(G-?hGj0P<(Al@l1Nwo& z9s*H_--d*kIbxW-(0SzY)*2EAL8Kxq8tYpCIzE8Ra~gQ-W}~@~GcEamB-{=GOwj$h zjRM^B-23G=O>7!kW;}!k^;W6YQ=sLdtha}A)ts$56xa>>DwkZZdWa9+J0Le#b?xavRe9NGRr>(!W{+l#ef1_FO>){=-$TQ}Td9|(g3 zDY?qm`(Zyr|17+Cy@+nJ2lT(1*FmjLBwaVDX(sX^$^o(8$htRywX-sp!SsGZhl;Bx zUbyAkfmvrgJVDT@6CfEnkRqney9;?rL?B>KH_)-6>ouhtf%eOV$Gan7O6;8)#!_KG z>QPj?ZG?l zhuZ-t5QzeVwk@x(=Mr^0+9$pqR0lk7zctyY-7gsTlTE*7fnR}uH!qK*7 zM5S{jS1J6)fY-^riqWgk7E+=WD=%CHU!!_?KZGIO{w1EvF{;FMU_PaOX=>`9sNa2r zJsziN=s1j);bv^$?@s_oYBhWMZ(k>|k&c1{L_yja9%Z{ko35K|?IuZDv0A=~mcAk- zx5jTAZ74u-Tl>>XPcUMxCLq{0PI~D>0@`)JQweJGPpq%$yX5acv2iLtmO6#esJR$l zWDj8-Gmu;*giJAJ{SACuZ*+}CGW6DGL#ZV*hN#f=xUD5*wKI>o>axl46y!D_61chr zUDx&FnS~CFNO>{u!%RpUFfrzVQ6q$30SPO^o58B=(ygWhm4OOId%(aS!ltMR!0Vfc?Qn z_d@EFarFjY!OWOvf$wcNKW&l4X@a^@G#UapX)p`Qc-MRhW8^NMb!<>$7g)D(P2t@? zU(Wm}12d`>?Lm^y_Wq|1xOpBuV2VlAwVmoduK%dx&qfJowJFV1LW1X^984LtuDaqkZYpt+I473 zP&MOlij>1ZyL9$zvb|EJOmIzzKXYJHO1TP6YZ(E$IyT!fIGs$Uk=;5LJX8-^gU%B%zOv^_V6k%t1pvXut-ql6M}TCPjEA|CF%+|S!|-T|EF2inL3!H87$;wL3xsA3 zA;BEsFK`hVAaPLCk0mU#@fI8fnNpfnj_y1Sy@cPqA;jZb6TejJ0r@eA(dnS<`an(D z3!)V-ssa0DS%sEaon+KKC;qw=^oYgOZ@M_sS`+r@xDXpJ4=Hg|4rpV}?`|Qw5hqiUP{}4SHWMS?~ zL;BeF1lNh$H9={)Iu#p-q0-!u1-J?dacFlNK;fJZNAe|**Z&iX2vKvK~~Ki-P3Bp%yBI|M+3axfFbO+Fa3_?h<%D(%INayCsU7%pQFnG9R0~L3&9x&scvSbo z=(lt813ft}!3{X|nppW0sUUL~y>@KOf>ry?fDccJYyKOBZmI4h@xj3@uJZZR>{b~-Dh zkUjTH3|&+rAP7d$3OBq!T0?Mcsdg3Z*I<~4)X1q10RGcTyjV&|k%bYd9XA>!kp9tx zL9C4l(~s33oqQQ)ozXZWX^cTR7x^%Yf5y4Ms)UZ>u$u39EQ?Tw~Dcey~?SPZhI7OJOxxnQU3}qyxP**Eq^yR$(VPqZyocWO}xz(>Co>Z+Jk%-~s?!9a?fi$Eh?; zPR3A`dxiuNh9UHsA!@4Y*v8eX?Ea;lMaFmgiGmoiG6e-Yo1zszC-}^m!y`0d6D>*2 zMMMVMIo45dafljewSa*ck=_L`9b)VBKTaclsMBsCI; zB4%|Ho%Wb4e4QK*%CT5$#pRW)#y3S@+9>siJ-4ivIoM(kszr|YCm(!0tC*(zoVMa9 zMQ#qP1)X{a_e?|YJMXZxU1>%uBP2HQQWN^2-M+fMb4RW8wpO~g7BqrpA_xtx#k;B`nvyflxI?+UR`5TmlA?+`bx~w?MGBQ-KfPcXS=S9?2@Fnf>-c^ zY(`d0tcEhPXdh@VewVskX)W|>GHN_LnSqJeRJ_NME-?Yc>!R%8yvdhvcDBl+9bALl zrtlfNj-v5v=ms~Z!0>qAaq3Rr9uuxGlM?^a7bPoPR1;RU?uaq054Z4V8MOzuL!<7Q zi~mtb8Jz0dnbU^Ih?X&H3pmX0x!#!vbh^}`tO5(kv-TgngST76stOCaPyKH}^KP3i zAqq=#-j~lZm-7Yp>NxsZK>(UlP3w913nE`en~lT)-qJn}zfN*wT3%SBoj#+x%cq6_ z)O-!1a%F<{g7cF@*VdA`d87{12vmNF&P1A>_1epgkMTx2kF%8bW=jQnFe9;s+YL<5B*;`*&6aNfO%H9 zxyTL0FuAsM@eAw99%dFc{OLmqpJlAHZ1xdp$?I;P?QY3|k?j$CqE%01CpG$2)U>h4 z&EyN%No3*a>;4F+1FIJfw@n=F#w?8+%k44ls{A>k_e8XEzv$m`NG6^Zp(d-Si@@0C zoxZxMB?U*zj4x zwi+!@DR#~rlM_MmiV!TN6hxYlRMvYX)I?O_yTTpf35Lbl=Z(m5VFr2LOMZ{3rUs%H zeFbg4rcrS;!0O5I?~7~TS6rfF`(`e-c{=Dk&1Vs{PJi_>w9X_q=C>CDFLER^rdwEB za$=-aP7L7XqRxmtPNK{_MeB=m{8A`epWu1ds8<%aLj)GD*S?P#nOOy@w`J!@B(0Wo zTi^R<|LU3q0*HQs?s#Lms1Z>&<2f5#jjv?;3!r25k1A<9puFL^iebx(RTAVQ04Vdc zLb&4mh4LSX$m0h@mB?vmHf{{*b+ida8#6q;rWzQ)zJiYv_u)wVo6F#}4AF%tJMe}ugOpeeNRB~rd;N1)Lr+d^SPKx?^1u&z;6ir3^{J+i zW&XRUeXM*P(O48Ux){Av}!jU}+DXLNq z0^_>ZHL{XGLdoG`B#u4ujgd!ruG7x>FVN?*6PRbUgA9kucd;En59HUXeiWQUAtzzH zdTX2rmQ#+6?SsdCaBXG-5yfFbw{oQLP+M-tesg%&GRIxoaExCI`$OXeT?vRHD zK7Evi$<`)Sslj>@P~$^~?3ZLS8hQkcxVz0uC@Atf!0ar!kJnXV7jU1Fv%_p2&eDXe z`X{z7)>yY98-Jt5;`ybvd0EIzzr!^=s*FJ)^pnUmfWniktkEyD%94E>cI#AQ zU=9sNA#2LZ15x1~v6`vDDTH|FeybyrW!q|GQj5eAckMBR9bS*t=>#WJhNwxQ=8yGv zuoN50?l)Wn+N~4dethdWo~kND;OU6$`m!2fWCVWFQ{Mg}f=oW}&a?DVGn% zg=x6Cx1r8u=sJFJqOGRY;pYzDq?fxeiR=5Dac)a|4hzau>*KAsEqMvHWmQyk#87|C znS6k|6E|%3BYqDAut)GDno0R7%%QpEwM*QiZxwE_0=T4T#Zc^$9%5dHm_O+Vna=C5 z#%tK$xD%4H+s9;6%2~1?)kg}GX?3=kM)rH1>B4%S6Yvv66w+pA*GcX2|9Wnk;b+Lj zEQHE!$O``@Op|X1&iefTIbpHo>?(_dp>C(z9b4NJ__igy9EsICuk%GRz1F!er+VPYifelV{cO1Tv!X?XwZ(Nj;JWg)aXomhi$aM% zH3c?q4_ImK(c8BC`F8;sqE2E6!x^$AEtBK8%+n*+K9YM~$kMk>BaA7OA0pilI4wy{ zJZ4Y;RBEUyksBp$4zdSxsN;Vd=N6cyPj_r}BT-9Lzc_lrT7CN3Juu3P(Xb%@qesAM&JbfD~zQ@~W`$M+pcw03zv+i=T#9K)D=PPUU(zdZQ z32mAkeud;fHOdUAjdA??xA}`ImZaLxG+e8D`HAiFyfG~WApwpuM^ay79+^oQzIZ@X zA&p*gHwIuiryYK$0QV37IkG3-{JDzw*e%bhRSB%D+>=C+R8VmJ>6$tefkXZjtDwez z$ch&X9%@)F6~%AZ)UM2O3+Y0HCuu&CS_F8jCi4aD3%SrFR1Z27p+w?dSG(R!RxY3B zPvF#NS8j8Pr10?;R=D!L4@t?#Io%a8Vd zt7$4ZXX>^sHK`^|q(aw0cMgfml+l zL(jfIR_b^#JVsExdahUUu{UKuW{9R#>Vq1-!BG;fX1^b!7W9(BPeBG5JnLdhm*VCj=8Di(kG&c?y5TYP` z#7VNr+CN)l_~=Fas=(^a^J31=gy9Q=y^|kS1*D$_)Afe@**Rwe|HbWlQ{u zK-tW2w9aG;?=~N&ga{M^e@qZ8L)e}X0}V!kqadton9+G2;vSxY(o7R%qb1;VR$cAJ z6M<~!k@AxdM(AS^DVXK1&cx;p+;^t00gq?K8DC7)63A=p76L$IAkk50(K3pJsTp5F zC;2z#=Mx~=Fdt7yb|b}=CO=;fYd0;3Qjg>iO}(TNm2iOTLgS$F5M0@GA(DChay z+E)loZ`6BCNXIHwV=Yl@3pY}8`!hm`5abF-N6QY3Nxp39{x$wG!09H=wFa?vf5dS? zws;Cc9`@LDS`|2T{Qfq+=s89o4wmGPbJNXXyuH{Wo2kUU(oK@0ect`|`zOosT3BTy zF6#uNAC+iM({8_HysU$Vv>T~;TXxO4M@4_3_85vbwf%^?t1A_s6A2t-f{ZBlb?-G3 z7II-?x1RBb_fb|Kl8-%8M-U@Lj6bhZM3tYb8yn#_w(#x`(nLNCD1CJcKS0b^G{TPM zEP_c*b1N%lJ6EF%e4q|Qu14zp+rI5+jVv;&6`-$21IU!~G^%XEO7K|7TBBR$aL^u4 z@RZ=r6qoAr=7y}dZt3<7&yAIb5Nln1Tme|F#Od9&eh|Jd#nhDFovDIUYsNr;FGCmI%c z5mUEh6SsiTwI?S_EW3`rpVSI7o2GA7VtJdNi!P1N{0=~&wUCR_UxqRQmTX?^ZlrBs zQ#QD;R?VMvv(QBzQVEAr;*570-$Xftj;;$~?zk{xDJI+F*&8d>(cDtrphy^y8zBZ0 zLO)xz79u_910@Z<}&E%MFb;llUa_4fFgu2rSP5{N^p=a>-X{CMzIXQrqP!XSE&;ksf&R%l z0#x20yOioqs9t9F6+d}L=_fJj8Q?=(W_svNWdx1ux<<-G1i3;ZVYw4REk z1FgXY*FsR~4G$yaj|sZC6Re`6F}8Du!AB|g_jcPoYR7#t6#WPd&Fu~OS^GutDZCft zxI39+5~gCicMS)&08Si-Mxv*h7>a`H2B1g}aw9RBFos2hg<5en-zR}dVTXLBp{0ZC zetB-i2ZdWO^ftsi1md5H!0HdBi6rgHk`cfX>#M?lc&s%>sf%fJ&j(T)2)l;6hPP!k z0q_fw>H^r=P8viDT`&+hIgv#Oj5z)C+2g10fQ4P!PB&cgkmMZ7eiu{zD8FHnNm*8H zo)^F+l|91YQ-j_hjy0@NByPF7kkTCmf(J6MEwWuZX40{gYq*-6`w-H&bRRUq%K9}y z>=%*rPXmq+gOKwpqYo>i8}XDv?nGE+Zt3+o#-d2lw36<4%-q42Xf>Eqw2V>?_yd%d zPM0PveFBfZTW(#IWPJ*5l8g#VQq7(|JHa^bY*<5W2lAS%!wVLu4BEbiptlP^@L0G( ze!~QFUZYja?McTo0)>76X*j|e?mZw_b-+O*Vav*3IrU%YcbV;>Z!fKYJ-*s@@@Hhd zGZg{4VpQYwL;_qz-4eK=W5O|b!lKfE9|!sm6Mc;R3c0+uXNWoW36`cm+5m_p2)g^m znq9?91l}xwnAP8JA5eA9ZTzLK-w}q!s(L~6?koSz?giq@&qIEfYnO2czesa<+k(SG z6_N{4RRwPI!*Z|p1rxs*d-)s|?xEQl(iwFkgle*cU3;Sy2iFPqoo~uS-p&s$7!nTtQ$g+|IMd3 zM`GmE1UaqPF{qZS^+zS=Oux{0*2K1*AJ1*l)G2x7ZUdg8SBmFpG&akh2CP}KDmHmH zqhYYsfol9JC5+)somricoSc4a?yXMVG@wsHl(X72%RzMTX&BCLYoWj%& zMxi6bluY@?*C8xKcKGvU>|I7fm1hm>$yxJncOk?Pq7~H0RvvXq_+L%pPReH%b zCy}~Gxf?{uD_w(>-7-R;*4#K{>|uFCk5UkGMWiPo;0P)}7r~-WZ+N=tP!n$!EJ2GP zynqQUF|^^|CvOkh4&bahVUVuaK@vSm*MBZ+1phSk=KjEt!`5!ll2I#4Rhs5cXGS^~ z?+5mM0`fy?aa@Z|U2NCyCY$srb*a@%#JLWZ&%qsFU`2u!>;^EgLa1SrZM!7U;a>F^ zcibd5>)zY-ztQs8p?r(%#BV-!Uv8a?iNAroBzTf3P%vp)^T^@sLT{ z80#PJLA8CpvRK3;0T+}>v{yIF&j1ktq()=DqocOKSaPBj!FVVpZ?meZx(1L;v2U>Y zZ&EX({0UDroCIw0M19otb9#Sv&Ob`1Ih=#dlphwbpmonetv(0)$GNmP1oG2mMwP%} z1;uY>0wX@W1Cv)CU?vU<7o4iGhQcMN)jk-?$w;qdFU>xw2a;X#D5)D(YwTl~T9|R` zpL2aiA0JN}h-DN!s(W{bl8*NiOPm5G$Cgt;m_46}E)+A;W(IhbA%6)bt*aSOv_t@^ zeIYqPo1z(sfK@e*_|XEy{c*(u!q1fUG7k0&NyWwU7wy%^|KD+&7uk%29Ia5!@mQ97 zu`fJt*XlyIlEovdfk?UwGk5dD_fY_WEF5cz&MLK|4v*=8H-) z|MNgf=SVR+`SMi;ZDp-oz@9va<_I|a@z`pLOJ9W;!$qJ#YB@uj*Fr&)wH__g*YDzFBVzSQX09vB_==q}vTIV3C9%R*4`m2mH3Qd#sM_T?2JqZ zhzB2){3Tfr+}1JNK70>&QsDHE$vAt8seED+2AOeC&W)HejZXj4GffQXbAtAb9A7!) zd4-osHm-QxwR4Wqma{jUJl31Ypl7uhl=de{&KxUTjC)_;Z$Z}$WuzB`9rf}dYfy{R zmFUKBZGVj3R^neZkvI(j#Rs8PB!i3^FZS=7#;4#;|71~~k(0P)bD6^y(8z8he3|c! zLoso3r4HkJ#NH>8!bS<|1d5^HNU~@K3yte`P8}Eew_^C@iIy3@H7B26I4|g#6Z{x5 z`l|e2*Ng$fKId{5d(!#b=oKByAJt#~5g=EXmOAZlg`s zdx6CIix&8TTMt^;=0>v|y@;y{_mpu?uG?{WC8m&oDD-XU+eM{R`D>T5i{ff-Lp1^p zGo1@iP}obisNn&cB*6M{C!VEb!^EvrhU$p>k^#=>JUO~0cUjpjs^QulK_5Ai#x8#S z6a#zm*@^-V8`%KfD6fGXGx&sr+Ni18<76oOu6QJl{`6Y^hUI2hNDp(D4$w-s+cddm zXT1${4C9v@v4ewXe7*b-(Hx8DIKOEOQ3Tm!G<$%m+`PphdLn!3R=-18@zhb8y>8#Mdm7<8KCKXml=i+(GNDXBK-b=Z> zgxekC=BbA(al|1+671-sEq&9=N>(O3J$p?59fO5*y< z(i5pU?2ODV-bWiqf;I+$NN)U6QO4pW?Jgq;F89ZRjBz=)BXZO(@H;eS%5BW{$oTklli*v_Pc4|YEiigS6OK#E$BdJ^e}ikB!^0`3dS+KG z^AFfkKrG@qfrPBF)`?K847x~5Qo0Qo6U|YDZFh=&9JQdH@6{W6OOu?caQ5}1-gFla z#u%k30;P6EZ5q`B)7C!_v@Ho@gj~< zE}YzN>ow(=Q(vG@u~GJMqP)R`0WodWbg)e7qL-IZ2l8X~+^QygkdEpOqCWQ>2)ixV4&S3$LCad2;Vr$ROsIU&%jUH4*+!yv&8J>sxx&?!}*kOV@UR=#uY{x@# z-O+s3Py*crk?Jy}sES4mj{=CdUbbpZOA@S38?+E7=h2Qca{I}X4D@c!v;gH@d?%jA zqv`wKb{zN0{`xG;TaJXb=#i{XBm`;I4S+cVVm2PHtsiWY$m{+nHUAA1sp1Ud@@mgoB?UoT zDyLfQW(x}5$~y2N71?E0F_vaD_i5*Vzi45)16}I+zQt*qNt8?Oi8uEEnwjk4J7(+7IM*sR^%LA)DXp)_Y8)6nOWVDC<^y$VZJ8B4rfc&n<=gXq zhm&ra0xO^1|KphY!P@zHJ~n2wlq! z_T?BMPr|h`R#Jk>H1UOKzp%3H3+vTT>E9EkygJ!Cu}_RwF}I#3Rh!6E?`|*0S3+qz z$k`+kmcdw%{RRF=5-OGj0p$#Ea(o0b*Q34L8f2cH&VTzk=j#J1y#R2|`7IA*Lt91w z(`p>-0rtg@ng{NVFO(oP!e%BuZ!nGyeTaHWTen0+u$$pn5(zsuflEc*mf+I&6KCkd zSggh<59leEMKib|IQXkyu#55Gm1rrn4%fOt1?#%iPk(@LRzV_$LI(?;Rxy5$9@w$S zKBYfWcfx09Y&jJ2koUcV>X;l%Eu#rukLFIsJm)HOR&)|KauA#UQR?5thvt~fUcZ-C z2#H$@325(;{zW?8iG`C?=yw({*LuVBQ!ezwYKl^3ky4%6 z62mM&n$-cET5`}J&=o|J8o5QNBgc7gV+$-c+PXB#2u#-w4l(L9u6B@~#eeAo-{=;( z|2C|(TJ8_9KsIzPIZ`Dl1TK;m_^k&A&H!dV#CZL5@#& zIDP(oNExxR_ps{L?In$s+m0^yJz@r*kfMHqN5ys5+jrMmns*|Iv2axDv=I&5%hp!^ zKqgEpws>mMj4Y*VoVYBVLL?*(o!T!T$+S+dbAr&BlPXKXLb+DR7in-am{SpiTjRZp z>fx8}OwuEf%IwR7yWH(g41;m{WE5#dpBWtXUQY^OhDtc{-XHd^W9*9q8ynO?A8QWc zNK9mhPd@UAN#=P}URcGs?ddN_Di%=z0PtG<)1E(c>ZMTZ=0+k}U0e6LjxUl;x`b;i zs)5mXojxiqqweZCHcplo74SP88xOth+V8bKF{V#+yaA5pzA^;BSKG1s`@J8wD1*jO z21A8mu_)ZF$9g_QkC9+5`nCjT%P(lBjc{#kMmZm$uJI(?Mi&0U>me(P?%pD{miq2@oS zKe7GZ*odTsdbyz8gQz!kxrg`l`_WoYCAKkYM!m$&mUV8L%^r5q5Qz6nlBw^<+%2HG zT$!^+?TxEkV$KRShSDO*gap&PFl`?=bH;<#k@PsLF{QgJg59A$5e};+?Zu=_(7xUi zQlk0!!K)BTp?;K%;(8mnXlQY5Euj0>#p4WRw``#B!ntV>q`;;o-DLHXV*7-gf7;Tq zeHoyWR@8;p(W0jH+Kp@=h7%#Pby7B7S5706e~QPEO6 z!b>qLD{_ez;hSky7z_00wlGRy%AxRTfUfj$kfs zF`dHb=&ywsni|rh=z3;lgMiF1%D^luV2oqQ-n6{lVxaqyOpYKFtGb|vr7bSAcmxqr ztQq2~I!U6Owm$SX=wEGvkG9d);t=b!|1pGv>?td)7l2>1ikhon#{o?)TgDK~`d3Y% z_ss}SHj0j?;JG4;n(#e(2GD?hL@=jEUAk`F>2vR^)_rwoa$UdnVjV^7te^OU?g?Em zR`yD#5SCHel8&hGz#3qewP%+LcYpc)nbg7xfBfh6)pR=if$OBwLWc-c)f%7BUP$Bk zFRt+G1Q}h)&3)MF%YI@E2NyF))Dt=zVDvz3h3*ACnOP%$UsRv|12pfG3t= zD)?i?v}h9&o+RtQ8X2+MiVd2;fkULz)a#G@g=W$wEE1BaY+O(ll8hXF6|{bDJsu{( zi(oWdVZ9uW45rYq%jR`WBcGl4P*c{&AZB6`T#Z2&Lzoirk6MrAEk7sfYH;BE?(!xF z4s9V8vXVkQDRLH##I&m?>O!-%G3I zTZL+2L8;Y()D4?=%T(iiwokXn9-M3zqzKo0PMa^uxaw)@zE!N5shl!g`!`oUM^p9> z-$A13j*PkDa>;n-{vw50s9i!sWZi42$=aZ#yP60qi^9vaz;+04>@d8>^n)q9%@~!G zUEw+5#X<;;uc9InC~!Xx?wX+rKGXD9C5?%~rxnczUHI>$O1hze1y zY2KowlRKZb1o^M1af=cU{>1OQ`6*gt)vdvAy2B8g>25B5pphk@v?xK8Ur6+)(!u==9kl_7wN9k4M>&C z<^j<&qyRo9{+kYdi2I+-;{nz!5KN@(#w<@-x8E%}Kwxz=T{p82<>~fv;Z%eT0x>xV z#;C44FBsK=Ru~cm1~K`g6Typ67%M>4&$Y?vR-}ag4s?XVbVAb_VKtp#p%ojUi-pLZ zDD8NZ2-aF=r#)6j<$|St|Begg=ddJKe2$5J=&&a*!+GHMarM z!m}04Gt-BUNB+h5%!^ki(A{5H3!IVeWph0ANaGxEH@cW$E-jZ8X6}o8P&-?iQx-}v za>B8}GWX*>TP-w-;D%KSUKyKM|8UyaTyAC7;RK2nUKcKR@o&G8Ai4q4iUQB{vCe5+ zS&*Q%5&foOo$_#HlT^3O6iZ&O*_Ogtg@&Z|bi7}jY|7^e?+92J#t&$RE+t%SG0!Jv z>L`a?@3{q(aR5IF$Wu|~reo5`iS|T%0n?@A{j3omRS?Bm;z%8army!SQr~}yZaYo6 z*V4;3ebIWc-19=F6J3qB3^~1PN$^>zHE>f+{8hBq?_?eBzON@p#AeCYf6B_p9}WwQ zpG&k_BwU(tu$0jM2`c*V;bX0H~e#p>KJw!i+$OsU$?Msb=`f;;O$hi)lKY zVBU{oA}2mp)@I%vcReR!+r^(DXe6g$VZhGFjV{8_DXq4uvCN5P=~{8XeBxP)QPGTw z`Z2O1yk3H=%I5>OoU>yT_DH9ei8YK75M|c*j(z(5L6%)YBhdQ%$eaMfX|-{wdIiqu zSdGS|OQMLP8|@wb1Yz!*v*yRNZ6ny;q38F=OPbi|EQ2d=2{+m%7(72lGJ{@l)7uus zzm;J~*)jsZCQ)uW5z?Zt3VeI_z2Tbx2;N82i*K3})t`bSc@PilR}r&qve7MS3C5h> z?rm6)^HK8>8pauoa)`_J+azEI=Rhm#DJ`EKyLavWH3pr$HIEdxItWMl?hMwEm1P4p-;-f=)uDeu$M%Tf^pxz#)5p*U{O%-AGZS%&swx(FB+K`e< zl>~5Wm%ux0>|)B%1%B}sYttKPNJPJN#jp0RR;| z=Mn<>1oBlPM=VgiX|{V7zEy>%*Crx(f6#fLTrH99WG$32T}Ce&JIA>Nn1jbC|72Ut z?N~jBkt?qrx53Kc%br`OiBwU_i^4$s;@6cXHjIepIB!INySjp5iJOzdz8?nFC0Mu? z@+V>OVBEcF^!+YL08Rgc`h~V|@q5a6L7Q}jk1&q)`srmOfBBE%YqhN2agrEXuAJaf z4NDOknBp-+_}w8~?c`hbWz23Cmh&l1W^_xsQ15Ll+Ivtv>0YW(wk?mm^A8<)vWG2Y zL!wQ|w!f~qiR6!VLEpSO{;U8V4!N4`Lt66-gwJ_+?P5zl7n55Gm#i7F>eR{d`fp{- zO?UEhb>EE4*O|dI+JckpGKFi{2ou$Y^p->%#OdI#g>4#Es$aLaKVpAb-F6tZ>VkDAQ;qgYX$kExxKn&v z+35JXC(>(Gg@h-c&Nbk88szC~7c$&VHqJ^AD_&WPYxdFZ%&Ja*H25RrYJaDjYlAAu zCPe0-n@H9At2m`9U$sl`z13~xnyd8s7~3_9ri zUyh)R^;-DmNGS|Sn3!A+un6s(&Nq+9C)cRz9=9gr$< zfQ#6$@HwS?f&2(l)WkvOY@UF)2|zt1cQBkXX5xbQ*pL$I_BBzGMNJ7C0WkcARxVC# zGO%?Qkp=c*%>45x`)P@5@x=@bo(gpReI4m7VXcXtv}%PZ$IBvL^zh}CJ11_aA@+6*lS3s8y^3vK@>qK|zGsbyuk zXI8WLhXw9*Bb=b7^ZxrXV<`e?bJLype0@JWE#vk4Yc?QF>TzTAD*==6wdnI`MKzYs>8&bQZwH(aZ1rsfbL&?v?G^U-^-UTWmN1Bf)=En}@-1<^Ln zEW?4{oya24-OS{8Iw4ZbtZk}s;o$KY@I`}19Jbk(uB&*!s%rX4l)$ZPfLY8@LR`$I z<6vBFsZ>9R*&d3@w%rtw7`Y_D`_yiwQW z%odyCz6`Qt;`YF}E zGwqMP(AeII(8JQrRIOg~>EgJWI!M$2n zuCV-0D}KDr^=d~Mzg-0peF(u`s9YyE-8*jR`EJw4tX4{;DQeg!3jH3I;deBA4&VNm zYTQdlEotVwpjOD$BUkt)t#tZSG18=KjW#QjvDcqSrJp-biw95%&&#)~S0!1Xs#R&I z-Qf6YeODM+U`yq7&wx?1EmlT=#w``xO&{TY#!QTY(H8n4Vlp)CKGGw~J7?sN>afy2 zpch7EXpml+uRXQ7P$E^hggaz(o#?@W=(A(H5obB!{4L2s=W-K+%9KKC2e3|0n;loD<}AUv*}O+)wybSH@=H9 zC^(xFPLkqFl9@xe1@*(NK&HSs&n4_+x=^J-O$rWqA3~=Y3Vq_jA6YG}CK6idTocKz z>+4MsM#+gCLP@GBPIS~P9$qaMgv+pO@V-fHtJhzE>4`m}0j8OiIr8e&%XH8LEUjrx zGOiIT+BA_6#F-9G<;MOvExHa6k(pa&LrPfyMsHVp1$)5VA~=W)X>?gPGxV#sc8-Bc z6>I=dCu#xS(nP7^BJ6!63tjU`2L2~UxEdU?HV2q@os9I5H7=dltL9KH5fm%{|5r0wtt-dWdp?md%9LO|eLI?8KOEXtEq|f|XvItZ%oAWPvZJX{AsQgUyftIo7Z!<4TAl zHNK^9{_gUBMh8(J$fi^z8+OD;Zn+ZJfMK$|tpuKNlq-$igQ|#R%rdA(#-p!(@kLjQ zSYHFvtpX+EqsD$iB#0dmDn?y8RO$OK>E-r$g6{30NS(FmkQ;gnUh4$aPzyG*n>lA6 z*FJ=wDp1la-wgyQBaDX7@aR%Xko#b!n?ywqQn>TLL*HF+mLgEq{OM34>vlC0sJf@? z=ccYZ{^)G5pe}ZzRi>4UK+67n^$MWBE)^DPVR3pJgGC@|cG;i}Pr7yXUtg@#LnQPR zr3DbNtL`pr%1MJyH5~;h^!@G zU!sqj{fQjItbUuw1n_TsK{5IbD|t`6_#Wh1^nm;uyLxBKQN3Jxd8(4ANJd+FAbrqg z{klffTrfK({XumU2*^*kWjgF$zv6*@xZ`WD&Fa zTsB(n7Gg1UnzlcgSW9I?3?8Uk)`QP5E!1u)1zMkQgt6iotSHT_AgRrwDIA(2CeXTc zvEJLj2dMWsDwCAm_Fv(L&O`X!?XXA7OUWN?C- z^Nr}R)kPbh+S`y1j&%Dy54(Ej{4^ZE-J8bNGmBoCKO``+x&7VgsLd+okm@gU9{K@< z-2O~k~?zt&pilN>u+OwG4kv*jty0M7W zT-4G$e);9eHH1%OWxXXuMF;DVNm)TLXP-QOfH%+yK|!(%!S^qu`L!XBU<%cNVk^_U zv6hhqm?la)X?2XJH8tKPWMjn~OSR%u0hqW&qmB=`2%}&`CU>~!jFq-&{DQUA?Wat( zN-{Lk*_O;mU?img*m#p`_koadDFb$9cwHrr`w?R*fLaNSa;<;KWNEtnuhj^oMW8T` zo(lD`+&ol%Rag=JG|9^KxK~T?5d|1JM($5NMe`9PslY85?^(e?2Fk$}Z$C@8+X}|& z-v436f=OmEbN~MMiO!`1^hNo@je}KoE{bt_N=y?ab}+%9pzllTx{pK!+2E* zNlwe84B?)RfK5$nbPZH4@)rV=+68w8J+aC)y7 zwYfz2no+SR^$f2%Wk$|pdk^YRvQ82-WT)#XG`u3-pW7ECOFoYm1)0Ny5t>lDk0i(} zcCQ*e_|vpaL$z~9sH6+a1Y!-#(Cc2#@okgI`|RgsV83LAG3MxZd|aPJ)LxtHL%?VZ z=}#gK#LNSuUB-z>zM=nu#^Yi|hz{UY7n$(fePvP11ncdEyyDaE#f3WW-loJsHQyS& zoL~Mi0W@Mm6{A1f-Tiyz#ZCn_^~>AVyoubS*GzkEqZDHt*SNs;zpQ>er!V+^-;%3x z0Bw_0pP2B6U$wo~P~9-D#b7&LeNr>ZPbw5Kg0GytYY%P<)uzp3X=U*<5-|};L9VJB z((-?YM2q=xgrW>V3(HIgkgze7tc&4T zYY>LvND208D=}cYiOpzkLKbKDh?3psxW<09ze3#i%`+76i#Lnq3_zyFL41^JSft3I z25wj=lATAkp0kio6;2RPw9wfhHTesVsY)$IJuswy7y#ePmPz0G_aP$K&`sD)Rlf@y zmIZ?h%LLe_<6-f97y|@3cGLFk>=);%eM=r9Qm?49mb*39Xs`FMg*|F!TG9maKvz%2 zsKrOKs^MmNW;0!X8g8Hxai{+2@m6H8SDHpPwOO%>{Q1jfHG_qqNd}dfKYm}op1QW2 z0AJq8^>{1`ehly1(FUqofz`@#1lSKhz$L$X6e1kvJs4Pp&pW%?C<9$W11l+!v5IST z*D(GW>%w)G?9J1~*1$X?MNdYRUN{{Y`Y7)kReZAN=^*i+mNVr?tF!wCb_30yg8VTN z1<}g~_vq>j(S~=XDxYQXpPL@;3z1%}Aq{L{efKVP@n_bzgb&raqdR^A#?#?8cm>6$ zLHODTZWZ)j2AL@y?2-RSHe-QC5^MD)&aFPki3_PSzmz7ezYsgKmXSHWlPeAU@p6;1+m?B7*2_SF54PtS%z+GR{d*BBhX!NW zU_FXj(r&_bty?*dQ@-_x158-Yk}FW9URB}hMh=nq5a>e&YT#~KeyQSrz+5iv0w;o&|8fCP_#^mvahKt?w@j}B6sLSV}r=QF8GIfY)2C((Ammaf8`s$C&#is zpNHoggr2C&I**oJ+RiKN#yhp^m9Y_c#}zu-JSe@&G`Y~Hp1csW{cEx9q29W~{eOPi zA7aIzRI&N4hup@l&#lJp*xIX3p(r20#Szk%J_Y6W2b64)RJOQPAWS=C_Nn5T`vG|J z)t=q)%=7e)x9*@eCbOJDbZ9KPNo%2r<`dcT^stFbvQ*ZB114&=sHsP67xK{XqUSS| zMe6sh>-0^3g98%+<8EYZ6M7$Va6_@9LpnAzWYn-lO!jY-b65s7AzochK}5jU1=?4G==Q5yz$0sILXnC$NcodE=p&sMLuyLP zog5=tpL~Pc;|HRZs$pSk;Z%aTUj~{aDKws}%%xgMVWZV6U;iFN!7h0~Ya7CJvjWr9 zet5;R0I&)(q@|BmtbUMLShqQ^C&v)HCR7(;KJO4Mbr)s;nJw&$iU$s+j$mpap@Q?nk)FP{z=AhYE+yg}~81&YG&t zEYTPQpW_db{+;#ZUD&Ix;bo&AX;Hd|n$ehs%MC7dGxg?uwcGKK@Ft^=OL}NofBxqX z5B`anN^WiB_ii9A|Jnk=wJTRF4z0uwGn)hyFHX6 zg>IlbAR)jk?vI z-#!Iextk;+C6k@=sD;OwBJg$AZEQ2zNv;pGb_&pgYPRQ5rWZ@wLI6*r+3z{M886cL zamJb6MI*5q!s5YNh+_vNzq3F~jlEa!bZ}mOh&ZMu26|L65rgM7SI)wy)G;ucCxqGs zp%pBOlC+Nq2px#zXcgkujOF4OEQ$I(3r9>kZ$1c)*UNgS0QfKj;JwQVyU~QDnkCW; zwQ3j06;Aul8f^$u1tw15$oBdjdM{gw-~#8ud!zJ*1EU;b^IqKYzIg+?sc%5%%XT5- zU*0A{EVK$~y>z7_0^lN}KIPZE;|firi)S*P=J6EV9{v=WA6d#s8K(n(Jaj&8-`s;A z8K=&&Z&4{b;5%0aKgHiXN3~gs*J>X^CabiDJ?#0s{=%8p&*}Fg-~HGAOHMxdlPI+l z7H)K%zzj%%)A#>Zf}jP{`{zjxN>Q}x%&Qy z|9=Qh1QkKPXpWz>GFXryUw421_Fqz_*;Fv&7-9E5!U0@;D6M!eOR^LZ#;P*DNk+1! z_9038ZyrjEzgrlGGq>ByV~uIn?HrE?5Hl%gcdvC7cFzF3IreG089EuxfaD^LU5$u1{bR)2*+Dv?I~KkiK&Gmr5o$;L zlj?>A<6Bxv>xNUp+I}w-=`*>oUs6b*Z;i)7Hi1TlK&kSaqNHl5P!jEPohrM`F5eX) z#X_{E;PaTy+x}>^`Mq_YwmrG*N%{&q3XSHIFqgF4s5t%_hHPGn9F(s;0b(kV`?TQu zml@QE2FFc9T*J%9uCOf@D zD&J-FtkgO#_#7Q0sbw4F-pm3EXUg9DTo<}&+#%-SuP3HMA2*ip@lrmnYt2&vysuoY ziXt#86)z-x=;;VUK4pyryS2Ftfd<=Y<5W||v+}MD($!1m?1c}G!n9CqoWUb32_Th- zg@&1uV3unB1`Qa!VZ6=c>wrD>C9mbMhVv&p9~ABCusf(FO@R0;Q0cp<(I~w>bq0YAGz7Q~U#; z=UzC5Q_R9uZO5{O=ETY3bkD1IbOKb+cXSq>=_?mT+L^=Xgtc{*fIiy`#EMS~Q9)S% zYk?8jho`*b<2ICHr2d3Y!M`b@kV{E18$6IT*{Swg+K;sq;|paKs>&5f0FH!VOGF2%<<3ebg0|8eG4lmj~1uga* zrtzg;#%4VQkM?To%B(u@fd6GgnLB8W6|D6JK9`um3gb-J=JW z`xGSHif)B&_y~2gm_mNeo#9Cpz$tiA7KtbB@e#<&>`<)40EC{aX>bswK~d(^QwcT`Jf!2k`~*I^ufK5?3|L%T@IDJYE@KK-i4slbur z9>LR0n95^Kn7irRbRpuD z1f=Kca;QkS0hZ6zcewPVP7BqCYtiu77V@8R;n1|v*iLeC9lCH|HZH$<V-oURMsYEcaQ93DS`!s3^UEo&ww4U_yHb1Y_X5)~?NMJoDxjHl1|mONT_5idDV20dR2&Rm zcg*6|?bzfWrpzF3iYQ18c|(k*VOT zl^tpFESpK9aCDZ3VY?ukSvc#}_VngttafiN-k!+AjBAS?F6&`e<{Uc28Vn!ayK; zDY96Nt|(KmFRZny|J!PuIso#c7!uUp7GMVb!p0HIuiD!*svEeh4R(9MsEH%Pp{XxH zd{pJ0Hgyx77U-md^4PRm%uspKd#TtvsYPKRwsV4%j;RG12V=O9J1pkMPQ?-m~;hODlAn~)mv zkp>LXZZl6mNZBk-77~Lx#cX+&v9zJVH{129TS9AGc{eP)`>X(*OkK_35t zUp{plPI0J}3t)5=te=`T^<0)AW$0e7^N2TSA~VK{*$0P4 z1idqaD{W(Y<@oM;6`kla$XbmrO@%hMk8b>#3V^`Pwf#z#+wLjLIa))KT>o$E`#jABylQl)aZ__sebCiFok=;3M1sS zyuHAQwfoJ#d6CPI3OM0 zYb2qG&uin_euKaz%2U%%3L_}?*P=!0wHhjCacw*M4M=By^4?V~mEr9{KGVECK7q== zATuGkJ{mh@stGYoqz&F)|E!#~&}Lb*mgl2|33BXbiOrU9b-PKA6HTGs#)u4BPFX&A zhLGKdT284+(cVqioZ;{`blfsdh+jZ=b?glHBrDPvc+mlrAr~A)ZX>E+(!!K^L@nD$ z5ywGbLio#~eXEf+-vwQCQ+slU_eTwWPl*R_tQ`;L@{Y^FQiQRY_}TL7T%XiCw9!cN zObpY7+bKuJkZ#3Xj1B;ZEt84wt==i6b`j#_65K%s$~EXqIVKlK+lOQSCVgCs$YVcu zKK>m#+%QQ~-|!UoOX*dV0p9Pmpj%5AiyOofw2{COYT5# zrF7k0d7yET{VChk%}5=d~vCpl@RgV+p)l zzjEqI*uOgD92f{I-N8y14E ztwEZNsDYW89;Gm?(RVI*m~Yt_V?0PM2)LxLkA7AqC{9Jtva>uy6usJ_PLzlBG0T$X zfDayfgt$%;wAKk@*aX2KcQYdM8BcBCFTtA)igrNR)6Pd9GIO&EN&HY&g1IiQeG^3~ z8#TjFcL?Gva8j!WMyFfWpd0lvkByBdyn3+e*2l_$p3=OytCPkd#>1k8>&c2cX4Cv8 z+Q&6D(D!3Sy|Es~`J6dF#0gX2p9tpct_iTuZKQJAFLKm_Hv;RV^GxJYIzLssQ+u14 z;iVwggByPUVSdH}-i==L=nv_VSXJupe$Q9*&^jlwzNi!}s#Oe0R-ziiYxZ~n;Y3rF znsT7o=L6qu@rV442oWMAt${5|(6M;8jFc-lF*S{1pofGgXUWsx(G@o2vx z%%Iyj(Dsp>#k0i;mbBD-5TD7Lc~I64&yapo8SNv8&RTIDBf&!$pV=LI+{&8)eF){B z$+zWH&=a6WXr*t=9_gGX6nQ=WRE!JQKIE@RJWM3z^-Z3**Z&SX4xB`Vb5Q5pH@jf4 zds{tqEX=TxrjxD9MBGAAFMV%hc|U8wq`}gPxpv`T+OGHN#avBxWctoHfRPG)mB!_-b$y1ahr(bkQRDGCX3av_ejy8GqWKkIxp^L? zP#laTHAPtAHl)(k)^ecKZT$UWYYX%v=;!_k=tLp;eK-SRTqkD>7!#skE_`h5*WZj@ ztJ2=%YeVf5OJ6(>1OvrkzO?{ifK@_z(k(B_(!#|=L&{|O-SZ{`K1c7+pN$0GEzYEu zWh>^dS@P}bM<#g+4B&~%cpQGZC$?lC%&*3=P>X#an7aYj}+jSvw&mS0AVUt`;*?h(i$o&;VP7&*!@?*sa z`dWJ}-B3zai^M2g!4Gd06C&Pm2h<}NNp9O3EMG$J#cH~_QHl-0wfKs?HHE)j7HrYo zh_PtFZ4i1Yx>X|$xfkR-)gCgRRF(fu8&%@$bDGd_lUY#eN^Z~u<4u<3iyzwzy=K(P zm)%HW)m?jtVNgv6VZXq*@HItuz*Ya)4W0c7s&zB8+KH^jx(^FNeqbGqFeH~|{i_+$ zLpTnFP_K~aY3mw3#=E2!b~)vtj`f1{CG;sY_&NdB3tn%1zQ+`lq7{W+Q4kmF-d`EE zS%bEL`fL$cdmMBM=3(A#&CPT-Cp3FpdH+Ui;~6{AMnK7RR&7*q<=)_tqpl0w z)=i1(44fA3RigUicFsh?`z+|-lBh<^^#KiZvz_|egb=}_Rv;2 z1LYI>l8mBaW+_ar9YwI!#P&;6H2j|N`)KK`RX63jL>ngBK^MAT074<)!kfkO$kcG;DSf*GqH+Gbo?J++C?r zs82nrDLDo2p;s^ zU}6qG4_2cgW`-fVzUUELQx3L!e|+%5)k|gA0(z~6WiNQs15=Tm46ZtM*u|p?=O!6u zghz?}v6YDmPT(8B)($4_J2mYDPyUlBK2Ts$Cb>(Tkk0g%K~PsBx{72?P#m)MwotJl z1>-9A!?5%dVZWKH=BUNn+;2*8FoUsS4VJd&N2|2GSGBjOvZRIt+YRAnIUW~rTX&qu z%rF)XNHOLfzXEXwXBfk-9#A^6i1nQ1@1R$_AZeAx5Yj!&mK0keER_2h5($68v(>t4 z>E^N$rPHPH!Q8i}KF!0$_yrp+6sZ!U_;Eh3uOj9+j6ZIqIFIr_FoK+CMrH;=Du)3+ zKMn2~RRbj!JG@kEPS*f-Ex*tBrh)Hhi>YOK+!o96Q9^0L>Dh6ppX48$#VA3kfJoiS zugXkRl<>#E^bm8I-hY69>sP4kc5GHu?t-?wUriVv(fa>^0G_UH;|5jZ#oyVZ>)`z|)ho!9^C+A@__UNiAJ z`!!M6)3oCiDtQ=vioRhR@I@8qL8KfjXAh%-EZVt;P9*qX(ces15g62iLC#vG`y&4e z9zZ-lJP+3x>f^mgvi)a*2Jkp!QP-Q-Q$_6QdbWkP8mM{1ZHsc3Iqr(V6;tdG`&^5r zIE+Hu+L7i?L_d3^U!B&>$iiBOQH!P;)igycC%0xTwpfRKH3qi5=GW?zg#;!;jwk|Z zQ9X=0J>gareW6U0W9Tx%?CaA$*g(|}Pe zi0cmKx1EjcAkkv-*XXg2&(Unpm9DNrnjwh+sNTH5u1~_IrM$fD1ZMbz{AG%CzxdZ% z5w>2zaIlp;0iwG@clnQ3xUOpGx1_t+Au-&^0Y}!|9`k(^4DO8CYCSSPajkc*#n<>h zK+EM5t)^bk-qbtrCk{h)t7GH9I3{})qum+jXW_by;J1yz{nr93F8q9-0ij7yA$~Y7 zD%A7#vmB~O$~*;~JfZ=!OsyjEo$4*n3kG6Unt=SjcqNZCQ*Trm&r8B$b#N)~a)zKV z%`2l8fO)U9=>2Fny>KEaQjq#lOM`LZJx48x)su)y7^C2tfJ2# z>Q~guBr;F^6t%le=vl&P(LoM{4;lZDhp^CtYZPjZtr;@Z%&aI>ddN84SW>%eJo4=Z z+BONDzC0D*IkZJ9Y~f1QvEH4%-Op9BeqazM0 zAW5ndI~yh5z-9A96|FoX~(sKE3owi4b2Y_ z@ddsKDNWt*F}-%-r_aa?;Qo0^<7G9MZcRAY`a#87j`> zk8&FQ!U;FuRYD|9cVTDjlAc~n@ApxFl~Ow~q>l|(uA7#{vk|cVcksV}TNiXQLUSmi zo4_DRR|riugBE}RipJ+=AEDMeA=Ojt{^H6-m;>Y7pB?|#>UrJ3aLZsd~LVM>nxSBP3hX1?SkR2ixKXRg&>!;Jh8;$IKNLOuoe^4f~iR zfAc<9=1l4@+?&)~EIWPs%TbPi`(nN!9rO(731vI5ey=FJJrUSCEg)-Q>{<(|UC?=DnE}I# z8`)s{8>nJ}prRgU3uBg$5Kkdwy2j`KD0#Gouu53(1jsMt8JQQrdBv2Z0(~J%G7CAq zO)^a@gpg!e=4`iYxDe%}j6!*z$@&yC7q*0&JLuJIh7+oXh>c~`U?CsefgbKA<*|}e zft8foNo-m}t2;nP$oBNsY!uyBW>t-UQzCWoO{5IC=&Xhr{hU>)4D_IDT($lJWNEJEC&REJ zSp(^9V2MUAyl5Aat+su4Hrj)I48nnv$~d)lz%I%D%2?2P*;%yK z>+-5{AC<%ZZ$69G-cYJY79|-J(W^_Ht`-aB<&#eh@f$m(pvbi~^B5hX55;BMY4~(+ zS2Ru06hyZm=_)hXRAz2_qAB}N$lHi_hoY4Vn6JYmV=|u}FDDh>9*Mh|V4y{KpG*)0 zDHr6i;t_}B$m9uA1k0G6J&L(@ko;tKkN1@c{o|k4OTJs?^74P;*<_sO0~QlM8?NVsgA%d7=8Z?>+_0aZz1e(HQ0V!B%` zii*@Po{6tfz8nuZn^RpyR2!eyU&8mBCR2+g@^<16Lud1*!r&5^YEPS)ubChO6Cr?>#MmP*SV1} z+9HxP)r*&*ygJWx|1Li8^Q?+Cx2<(848*kd*0)7wu%a^@IgvFIS}{L6^Zp+$O(iFO zt{|93??^qQ&WlIM;{)K6Vt(yfif{mF|1=lyt}Xl2VHL!@Jo!?G#+(HE8ylo!cB z$-NYQkkhQ3N;A#B#Lgfp-eY@f;>u%ytsH$c76~#)6nO%)r2Jx4a$eSL^>cL7*K@u3 z(i+Ntd+J;Z?!7PHR`%2&$nH*HjEH2yy2A~ZpVl>m@mDzfgUeS~ybCLFL$VPl74~$x z!xB@MYOBzi>KlO^!o#2WJ61U{kZMo$g-k1> z%pJfyMS1|v-b z2-DMDWim7c8{K7i)ra~BB6%_U>$&<6c931ftKniCtV#N*-W}q0>1Xs)4_lfye-}le zp^AtqPOYC+j!@vJ!zL~+@u*_l_pf&%#5rX>ykH0di85epx z&1nG7szC0O{XJth_9Jb&sjt#Dq~Ms3T5LsG^*F3q{8s<2j=#pJLDw9ed%T;B=CFU^ z6PhLcQ|xR;=zy0QBbPEi0^iy1>j>)}V(;l!Ne&B!QGrn5LuSa-D`dr93uN~`Ft zSAt3_Q5&j>BD>G>ua0VZ?G} znEOTY)&W-v@8PDGhO|-NF{4i`#PT@xr8n!~I0XCfRV&1#(PcU8UCow?h1R4}P-+w_ zbn`fWuI$%pQC~XaCR)#xGjU8T28E0S&#-`uunk@5Dfp#Vt`Laeor9->cV_sBz~Vx@ z1v%HFT|3DFw=XPIQ^AF3^{TI=IW#?7_E|au#4jMle*h_$STC-pdoc zQ45m>Ck^0X7auZSX6M)FuV`Ku2Y@kxt1oFTV>FPE$wd%bAa4oxIgBcu8Yo@{vh$=b ztK)70f-}aTsPZ{{AqNGViWAV*-;op{v9L}T+cv|p;gA?)HbpDVNTl99#8bSR{8K@Q_H)n>ZjODz0miz z6BJc2clog@TErPF-;!vw_cc1cgh-KH3HYsqH)#O1@_gcREPc<*h;v8HD!$gRQc4of zK@b?Y^wLViQZ*Ib_D(s4US|@SzjmajXB+{VpPaCN%Q{J*qbC+iE1UUgO_LVJx2uJD4f>1@Dv&6=+cygS$=fe_j-#$Go zhjQ&f1sc;LCG4e6ptc3KKKzg9D8Knsmy||lefM5Yn*7ahe&&ZnM`qRSTb<{r83VVn zID&cn@0RI|y#9$fy17!O88*Dx^i4tG)a{e0aI8)Av=t7iY1NRp1F`}@fCEb{x4&gmVx-QMw4ka__xmiy>jGr7GXTstYn zX)Tm}{wiFCV|*_e#j&sL_tLvs;%(8`gB(&@xu*J&_?%l_A#H%4Z;2%gBEh%$#g-eS zd0$$4t-@IR0a`2W1?}R$ihSvCT0uXETFGqlx*r}hPs8zxB=zi)8AtK@43Pr23OPZB zxhRe6x$Ae*UMxdGh-pZs9->6hG+a7X!{q}9M!Lco1T{{WO;ew!jemGDvurqt?rpyJ z@5vrZ+|EiX-R*!eHV?D_O}>t0J26am{13RDIU=#RHE(A`6AG#If-Nd6egYt|09CWa z){cp|lg|u_&TQ9-YR7sjxkl=!BIKC<)4gpxHf8}bdq0$s(1V%VrORs55CtYtVux16L;a0g?uzl zj{V&x(@qo645O}8{q509T6{Qu$5<#?dlyA#=F|dliO2T)F0&peNK{$xPFA$v=janJ z>WZY9TOj~4Qbk~=hqKbz?txREIJxAu9&#Yrxf`l*Q?xY8v*CnUia;YiBd0Sp`HUhi zV|=hi=KS$}h<0%W;_QIqHo<>%MVAh>G^(|D7-2K-cBRy6&{P#hw(fRnKC!Ww{v`br zO!EHK89$8B@KrGS(^1lVb|UPj%rIja z(SB)^NQSZ}iv6fvZP=-e40ry7fnyb_$AeoiH~`BuW*!t+x=X?$Wj+_`Q1K%G@8Jg~ zrZi?*_eQafR9-s1O`wA^425(iC6ap8xqH}#Wu6-!_}dwTKNQJS&fY5;1_r*S({bIzstAWhc=+Ld- zWXR)jk!7S+tOp6fFeQt0pO0>_rocU4gd9jfAeT2Nhw(1$?nwY5{^H+%#-%R(pNQ8G z{7z+Fv}<3DbV+t`*QVCN`Q*NBcF!Z)1{_$0+zIo;#+sCrPxjWsRe%6EROZ>+=ZN-% z6YNk8ukR(1bS-r*fzC^=z!Wo5QO_#yB9k~cEVT1pFHXND{b{(LD+ix#nc!-^S1i0l zK)a$|V#YNOoURG4Vc?nlD;EMXHP3#}W+{p!DGa+_pm>lz=<1}rEfCL#r=YXwS1ybf znItW*a`sPjfKii&(s7NaJrB^=GQzD}3LP7=2&b{L=2T-54PKa2g@>`!MDR_+qz#SA ze}o?_(1SCt-d=(&0lsw-AZNo?Oj4k5k4FyK74cICVTmO`sf`@rbW=LaTbZ6TZg)(IyZs_zRjnz=iq9bGs&Av{eyoMDjeHg zw)j-tL6bd8Eusg^elvJmhU09MqAgi~J$+D1nj&8kj_XlNH=6lTx-c_-3Ggf~;Qd>Z zv_>tRNgZw=LAE+z4~rlf*XD^EA^E*VhQZ?Ja4BQaddfZ&nih8@o+>4wE1~wMP#r_V z-cE5YLlCNH#;yrHxV_a88;udZ z{kEtg2bk&amk`=yS%I{eQ4}gpMPeXe(9bpkez-G85#|Hld%rsoXkCYA1*qk_r4qkE zKJkgAUng>b@X^AK-f8exrNd@=$pKsSo+tmP>AjsR*b+K&xbkEjVg|1TJQ=9r56yYCn5yGIjTGsB`;kb+XQgNs*L+tsxjBI0Be(yC^^ z?0;c&{Mrc0O4vSk_y1y_CD@9Aq!jCs8iJ{Ol6Zw15$*A;7Xsh+>Rgz0ebgI8yw|-R zi1z9PWBiFQ!+j?1j&l_;TujKXZyw0j_S$Ue9Zx_q%WRk`J-1UWW3k6%fx#8Fh4cxy zDU;9d{a5|mW|h3>GClK$Dv?#4{{9JI5484a`@K(jj-%eTgyeh#|J_`!M& zkzy^84py{={xF5E6GI1uj^APD6G>AUhLwRz4yB*c^Gaa4SLdFUlzYGxqDhcF>bFBd z%W;k!VR)rpYZ}gym@0r`nBu}n#)7;8*$9~7#iF{)vhQ>XpIC6oIx5#z`rgm4(K?#v2uE^*?CY0FaP z>LrPiKh!bDp*w^(yNG+&Tyh46a`Q^IPni8=K)3v_K5P{{&CQ@h|rD@WnM7kR_x6FkmQaxG{FVty$KaE2|YWyay}h4TEVH=?_#nKdn8m zX;v+VmX5Rxy>Fe12_x}9BQldF)jC6#Hotu#t=xoaQUO~7HoqCd*8Ib!%$D>Gd0v__wUqM11 zh|=31?jowbf7c*wFY~rtBZ?IO*Bc+wKZYQhx75_gSEzv;>de7IK5kXy14&`;1Ql?$ zV(ahU@iz%0eK;HF zLPm(sTR@6sH`joXB+bEE*hAIc`5_zdC3H1W4Pgn{h7PR>N8ZBcs^arj$xsId3)e~< z!xt?kYFLaS4D3YbF$8~WlNcCvcIdvL)h49rhw6MsLL{vKnrB-@BN!|hnyS(w?fkVnLXVWXW*0GoNK0HahIeY-GlQ; z27mrzhi9^sFn88ktcP<~(nQxDxo{?_5heu0-2+M*mG+^-=?|>(T-LbitWlMP^u^pQ zrUb07$J`%I59$lYgqUH4vrP}3YJ6p|Iv#{%F)|8A44w6S>W23(If&1aqVg`R^Xh)( z#nFrG%@JZeu);EA{W9@E_25j?%pR&dNyNVq^vSga`V^(-9+2JuIL>^FRA+zxQD`LJ zGnvB+yaRv6>J2v|JccRwQF^>{i!+kf?`9t(ZQ&*yq@TBL=6+d%P3WKx`+b}oz*^7~ z7ncj5dZA-=u>zwru}qx8HuiggFf+qzi*Y`i8IR@!S_~lxf?$lr{=uJvM6$o?!~D1q ze!k#6>;u(8`6?B6*X-8S%^!y(F_wqM67Aa5)8aH{wKH~=J6m$)5||B3gr5v;tDjT8 z$=kD#`#j6xb1H|+FdZ6$u=*>LyEhVV>EzhLUd~)|72h6;hE%f}iM17}zT+~X<=l{5 zFKH!uY)CuxRhUg|+#hGu2u3Y1FxOumuhNw)8^U&xwkXVyxg{$=*xyLy;(le`^D-eL z2`{7BWRBk*h`emL;=QKwF;Bm-9 zG^b6y+@q&h7?gwCE5A%#MMYOYUX}XZ(ApBcF-W&z1)bb@ddKUhP8&l=0~-XF0tyIW z-{=URs6e*}(~}_6Q?>&*HgU$MVMk<>JXZRzf`#i4Xzy+c7(y1PrDiidmAPa__7E?uFY{m2F;c#H`g#Lwvw_KwZM zHif7X7^+#6r<3_1)W388zydD@P$kSLe69+0F8SUBTY?{@Rb6#>NnDSujlS`<4x2>v zw?@mU5Q3FB(5;dE#&aRNDWU95727{S>9?`qG!^}v+=E7j!kBR&CrZ*5#qZ*MF6Ykh z*_M;%OoEVc9v#s#CiA4E!m}&DkHC~6=$qZP02ZQ{`@<*$@apt>e-hcE;Chh{L!~5+ zK{zdvS5p;gRKD#Zv4;>oY)LfS-X~VslQ{%)@wOR~ zTf1IdI|MML!j%;MLnjj?+Y|PxZ+wAt;)>3WJGaF}$+Gd9n0<5bdm|3tcY`-))s{e4 zOtWfjpDGh2Or9FBlIVBdMdEV6su}6iy)g(>`rZSo8@hK_Oe$h5pFcAP%d-~j=y&x| zlECUNl8e~}A!=ljEjobU@&1)Vg8gO7@ML81a)4O4;GzYIIL9d!n;$ng%Urbn6i%a z+R8P*zH5OFuo`>9RPXyF1*fcsu$0j@bY8@U!?@G^O9DgptYjr`s45W|4|zi9J|S@1 z0^m!=Qq_NTdodZFvU zf6a{E@^hl!Nav>X7#Stuj667&EdPrf z@cVPd{_-rZmK(+3i^+xsEtjE)fPTA3?&@Ss$Sw)*ugO_o5qvkb<%x`VNL{>X9hYTj z9QZ+1!si{>kUYxwYTpU~0|fT@NKD{8;3XqXvCYD=M8+N&O7oag*UGMhrY@Y<_g z^s}Ud$AbPk$4c6EI*p?dlL-D@h(%Yt@af{1BU>lBlXc>LU{FwMcv>)tRuNSFprEXGXSDfjad)#{BBPKuGKWbm<*T%pG+aX} z`5f4v1V`aLJ1HNIPP+yxo;z`t=Cac-HQr&PhNsKG*|{$~AMTWZaabmpruzm(>Q|yg z)mLgQ8OItsd#CX?*ef&$OJSt3hL0`}-LEC{^IH4V&;n7Yp!?KszAHBzNaMn@g)oGP zeBtjhkdLHq_D0;HXn^BCNY!C1a^69Ai@|#`Le6i@tyD!*5K|(ID&3Eo%Ck5v&IUS{ zwbM)(KDXZ2*<3QWofb3?+Xr!@oo*J&4ko?e-CQJgwkDhtC>+fI|33i0RH52J5dlP@ zH{=d)je=i;S`LTnI@;&bP35M84#s~KBqsH+8R5MVSjWI=z*galch1Y7T-;&3Uf z<5?=J?hnzu1M*A;)uTOjGF9MYKk@UhK>&|I#_3q z_+e+*l`CcwDaT5Tnuad_Bpb9v6HYEL1(B@d&5T0RCWcaDixCS3!@ihw(+q*6y-=m? z3$)`ECNuFPTjF4hLqxdj$v2!cqkkGaDn|w!*vLw&lrs}p7HY( z>)D^zoX_37C%6s~CiyLhqfi`Ap{bQHSeyhPMqQjMwSD;+gp$e9hwn+Cap{;f!U)Iq z1{R45#2-y1&5(7fz4gfq90_GrL|Pt@rDPV#3t5XUd4sah*~sl!w#VVPAr53FmVZ&W zhpflZ(#cI1qtk~96$>@>_3+fc9{s#&0+|2-D)oXTd$QmwBbt2{{kx5mdLfsZ!UHK% zz^;m_m1mh?Q@7JYY7G7p&@Ns@@wlQlutYu3U9GeM3H6SSFz`o$VombidDV$fPgt1`7js2!p*h*$hxY+KPSq! zG{ap7l6>7+32l^Ho%~E3sYYOjsAS8Y!pA3bg|3@!r`cU_us0nUQ+ZRyXL^GD52iPt_@=p1c`TN#Qg-b+ z2v^Gv8A~3ZHP}uKG0Gijv1;9ZI=6`Z->Utdq=&{T%E|pkD3qodC#xZtT>r>_q{F|iL5t9je@VdmAaxfVxzjm&G4pcHGdz8EWt2xaaf0;U%1bgW z=f4DvOtq-%Gf2k~<217fNrk!eaie;eqj z@|Np?1JJ^9u3*q!@cH#Ez2ow?qi7s6mh62P294OjmXriv|9$sq+fGU_>>wW_WAf{} za!oR+;AcyPmK@lU$CFEx9S=aEQ8gs49}kae_U zP++QlV9m&P!pJBKey}gG$ts?bMdL#W!fWO9)-7BjRqf(sG}0c0?EOmpy^P^>ytjBM z^dvoEpIu+-(I+5XwPuIiM!v z_~{uqFgCVTO&+D?J6T5JA*E9l;8aT#<1xybD4Wt)c9;#Zrl|=2Y2EN5cIVLhPpjRV zoxgMUrU1pNv`pFWRh?Dh+(Dk8_ZrCvuePs7j!gOmR|CVoqkCPde{RQEfW>v(Wm+AOMZZZ*X099xuBtIU&`49sAqkGHWb>t6T%^Vm90%dJ1`TPg)RF zXOR|nA$SgN)plI$Zt|=g0j<*2p3`&s{y$Ph5(qxNgfO#I{#wY`$gH*C#rOJRLogw> za0wn>0+Q9kVd_#$@AFn%izq%298x@$TcWFBR*sv%d=r+7bSm3847{N;uI`k2%J(hl z+s*@dFqQM*T-vnhLO*_huS1!4Dv_5_Xd5}!e$8%D8`64H{~oVa^N_Rcto(&~WQA$d z5(p3361DG{&?gh?_O6cxZuF{$NK;@QDV!}52(<*gb4MnO(tK6box4}f&jA2T5-p}c z>z07o)c;IJU7jPq&NQy#LMU;XR8&-%LinwM%;l=3KqA=wTFM14*_^Fugr9>(c-(%x zx1n4)2~8x7TooXSH3TU{SQp*?Xl_EisSsQ3vG~@#;@vs^^_PH4jf^kl27>P^fsqXZ zD|$(1TrBiYMGnN9>}STAPa-C0UA&+)gEfFT@%7)5xKk4>&YfIL*N9aSS3_H#f|#{= z`4rfSAZa}Ps(!s(u(mpP(w@#dv8~i+UR<-K_i}uaPwEU7!E=ybQzq=9L93&zN9GbX z0(?cp4$%JOmy&!F^22u$tQ5_F|7^0UAKrHTLv8pw6O^cnTrbo@E&`I5_jzRBLHKY= zhm~rF(4QXr-q4^Gmdr#|zWTMat0YI7!p1irf*C*w2y$AacD*9v)lzm`jO7ua;w4mM zVxCb03mp3Nuc3D>o|#<^Idwd5ZH-+}?HFUL z0;cjhC;-FL8ErDRvp=w@0f9V*cibM$8MLO%i~)8FJitfOXLlC43KI^%Iu`3~X9IXpI;_27w_ltxr71clNJVJYVAOB_+y-9?pBlVyBncsN#Cnv^y(Ah)7PuVaTslnrOZC%s+v zFqiXmXrIa7YuX$nF!cD@)}$kkdn#0hW@1h3plyJp=NO2}1sWlZrVa61@L!eSAOj1} zNf-bA;q#bRr6AK_aY&E$%@teZ+rDti>MbYEJHP69I7%vQSDWa>C4G^d(}gD})k8jl zY(4VXlIKYj*VdU%8cSD}in6>za`06%4vk8yk@P1nV%yZkzP@(?a! zqYc_NeUT{xM4UMaPc{uvxf^Rte7BO%uCzqv-lc!tcjV(t)|)5B4}$=y6cBa<#(NHO zWQpfh?GN#&$6ap`NsU(v%=;Rc3%)2Z{Cn5sslE^h{6uOBD_?^39B+n`LWhT+ zlh73CaCRtHk2i#Qjq~v@PSM_^KnacKq~9ALkv1r-e8uqR)&o8R0W`hRGAMnI>~YAj zHoF1ky1PO?tl&U7s!{|Xu)|n;b%Ti2NMR7#SMYPKS^FP!3#`r@U3LjUB@MM57BaG; zAkhmW7XFb`LB)rD7T~w4X4+>y(`+aEw|k=E6#*fmDF~Y2i03Xz&wdHhnUaE_EdMSE z@tk5OSw~&nli$bfshozr!7d0ANw~LV+x;z`$?NLT1}EM!-UR)jnV{0l>In~#gJMTj z5f$6ROw>Bk0ltxvnJ+$hmRyw@U&)X1dhqHP4O~Z{4vLr!(1Wq>>PTla0eys$Z5m+e59FDHRrMdUD&hKSvn&((FNYPL2(qk z%GM;xU&i$^L0_oSiKIqL!$<;0MLBdcJT<@V3pC9+a12zyWAw9_DsXYW|;DR?jm26H}t#egg|?+C314`_<8qLz~j&RDBM z)64u`8rF8fb;x-kCFsC3PZ4u$JH!As_24-z2QyE5F z3+#XrIc_Q1#{6&r_Fiki$SGzbS@8LKT6+V9_5RRTWZEQKW9{PNpyv_JO!Ls2{yGGM zn4AP?SejQRn+-db2lcrlG*T=RJ+?Gk8kgNr7>53`8sCTiCpxB3gNRJYTuBRxkIYUV zfQoZhLMSSQXasK^ajYn8LW)xR z*MjOdr`0lr3pS}Z$V^voP8;5IlBv>;nayCy_4p5+BU<_aB$f_%W3Ofj|Hp@*R*l{P zUhg<`iC`)#a=8+xKw$6yZKoWzNKt{^mXOXMv#)q6)8z^hYvP+*_?rzYVyCBwfnr0YZfJZc+I1%0y?_F21KoXK!^r7mJ5aqk<#dy+dBGEgU56b)~ zg)uzV3rThq0`69fQN@l^GR3ts8*Du65(tB|T|_t%6tKGN$6ON#fYJ76rCp*EQ)aPu zQhpi~aGv4EM(TTec2~`_*Tw5YT%KkKUX*;eHy6(r1d@#V>pNEF3oC|ibqvtmfqD7& zI-^o?+`%JOl^i9^%9xlj2sQK85T}IjWFXV;&XXxL zpDgh;_wvBhi$7(Bs%6QZjM-Z4iD)#X)UU$LPi44UQ&y1;OA0IH~O%UMj# z?EVj}c<3-9BJSp%_v+=Mdp_pRB?DOiYW3QO_j-Mn(mZ|~LZL@hG zUB-;e530&wo+&Y}!MfWs$RHG#LNejx@JiFh$Ztq%$dK$cPz=SEivaC0xt{{9tnVOw ztog5Guk(!fV!60b5QP$p>Ihp@@N~ZLYGxk9Vs)-HDdv*UI(=2&0j)$F8kYaH!KFVR zIi3C z;zP>tmc(KH^3d2b@$lJp49o~$nAzUrTL0E{9V^Xl?GOyX=9UhGw_j_tuGndMahPcW8fwr?+N9VO-Pc}Nt=he4CL zfNeS$m1cRNAM?gtfK{Rs&kajzs?vl+lGp^q?u!1W7}hoT5vf@!{7=AAR_+aOqzQH^ zQQ@wu{uj-ltDnGI&_Ihxm=GV^EcyaD3eR=fS0JR4S-?FpZJjbfbRD#;E!w?6)kGFP zZ3sX(VgY#(j!7ewiD-yV%RCxQtC7yxmV!yLRS)9spB!XhC(Hr1^EXA0z09qZ>VT}n zfNtP!QC`+daS0QR(iVDG7_w|jp3g(9;_b#gI4Oln)M}_TLb;q{0;0#mz;tZK2BUNr~t!jhxG-yI+8xOL(Lx`NtR zpsjr8^|NCI;c)h=uI(5UU*{*qgqJiV5Osbe7%WgQLFxe^urb9Xkg3-&e$@hQ{)?!5K5&3y?y-6BZ4dNR7M3x%Zn#>^vb3uiy*=&!3y4*MR z3UggYUF#8#m$gfH?xjrWDfabbcecj~?{yCb)d`@@ajPy=coMvU8-&)46mJQz&1wl; zGrGsJ{|G2{?ticjm}J%?Nt(>UR1WJWHrcPymZSz^wcGaq8M_t@#X8OIH<2(N~8M59NeHN>ntb}ulVS51`nvu zr{cM2^5SvuL64~%wUKhXl;Ra4XD7HYTDRJIs?klF=QR24!_;g*1M&b>*tGf6+ih;o zUP2)rDCq35nUlCR>x@!0tLtwquEkc0pH?d;2_mjpVY|uKw3H?PJ=Qu%yV(p~LTZoG z*nXODfr0=#+q4wQI_A#+vtS|WLHhI7Y)h^Z(N{fDH;$e`m_~9`ql}Dlq!)J)xa&Ta z5pF6>5j^eyHD(9aNm2M6B26>Q+c9J?1`^gx8K?N5OlkS|VN5p6U^Or1*J$K}>XG47 zi*50IrqHgGnhcJ@xjkGEgET^Sa-S)7d|8UmQG3*9#E=&~n+MStWCRR#@^5V7f6*{U zx+gsj*y|eUAH4=PM_BeMNuFHeNVQJJe>@5_*6-e(-#02DN|6m?UG_ZCp{~D1tsWxK zy|l%E2fF4R1^kyZzJ$%4q=fm3$LXQ zwV-0=qlt~pUNw-@CF+9QiduTyCZv1wfKy_n^Qj$6`VYO{Xs{r1NlCQg>9m{cl@Z+ls*#@?=X}UP<}iJ9~7}&QJTkEpEgwl6ZqhnEZK0v6}7%OiIVqX-x&Mpk<%5AYT-_E;?IW) z_-=fEp9#KY=T^L{bm-e-&^ByIP}J+S?b$?C<2^XB)O--Vz`M$RcJp2yMtrbXz-mls zEqs^DEJygaUl3SMbcW$Nu_8xMuKclhcD&l{74JQMW1JX$k#T90fOiH8m}MIqb-Y*B zU+MqANSW5hLVD&}N5um2!o}`mr%$)M75wAmBfBZG&m#)D%)%OtqvYpIUOl1#2<3faeG(7Xw;zd$$qx5E>_s!t#_$~)PxJK!q3R`h(t)LW+D*0 z=I#J!<*2gubZiq^!h68}-9@49r~z3d(~ndXF(5sDTM?|SPS(#Sn~G2r5u*;g2Bo~M z%xkEB{h5oO<<=SpaW7@)?E9Q*zzg!3zCe-@#q|4zp@c5$jB0H(n|!hci)qbO7T0d^ za?&h*Y9(NMV2h*`K_kaV*4}Evy_#&dkM%?ZnY_p0b}<*R((O+UAj})Re4@=X>P?+` zzjYc7x!Q8M#(TpUE|0t|C>cWx&mrs%;w90$fuYZ$#7tvcPG6|OiK&}LlWDS-v!th` zlWAchptfa+n?H%He+eY`Ut%=RbcES(_B@KMS2KFEUUBvz6=V6^!R`tFId2^B7~4QM zxAuB`Ms9b9n|lu2?D&?R&E?P=^EA>TX@NxlIKGAMu9VLZ`>z*UO< zckBx%b^@H| zK`M(-xI&x{5s}@GgH%8A5Qz||femV4Gqw|K=QvM+k>^EuWSVnc$yf5ClV>$HWqN+ z$iJ%;N(wefr%XV-q)LKGkfwajQ#A0v&2=e-#g9xMWHYy)_o zBaAPgfea8$ow+R!7(`YOF@x;56@w&gF8>QhW2hdB+3(p_!rLqQ9)>|EWvw32;wo&A zZ;Vfx&|y;|JdaezYNQngif4}4mG<;Mc&(uk>st35A+hY2^`SBB+WegVAUaH2fH zXnyl4joPv02wvLkIowVI(C49WsYJ^KM{M_%j_#QQS}$>hzJV;?&v<}!pO5=Dl&zKS z;uv8O9sK%M2lSvCF*2ClXDbc`nUH-HI?VR(Q1skhGiKi>Vb^qRKgG@j$@yiIY& z16i6?Rj|f9GiuAm3^wO0%TuFU$8@PRL5%F9b4PM5_JNumrXEsPL}>D7zf8f&xm%Ja zJEYP+hqhcZ)^1{po9;v1CA8xz=Aj{RgKYqxA%@&M z4+T(-`km9Db-oAIK^J8-YAtSGA!rwpJ5j-6X6#@TF(%0*0>h{gP(j8Ji0k00L2AEM z(mWuOI)03mXhKV+HdF8|h4)^m?g;*zy8t&)H1bHWw^m-fAZG?5Qn761lcaR{=^21x z`?jD`eAITZ(XO@wQ~@;S0hL7nhgrrbXigMRxI6-W0ZVGX-*_@~7Wf+Xcz&A$?b%v- z&+i!87AK}cQ)DG&;}GRB>z8jK)orb};VUM^d%8nKng>6G{!#K^3}%vCnx;zKz6bGL zEbf3`=hX*BVz%|xZpW4D5|h*V^?zH($-v3&z?lI^F_>qjA>>(9JDqO)vXugfq!E40 z9OstyfJDFnbnOVTdP_G|Ae6yHMWtz$WGY{qnM7#hGY_(eubeIwi+xthZ z(Jvb7M`32n{2c(}QclVqna;YMp`c?6dO>EvpsRvqS!n=Y*Eiv*TDynlta))8po!4r zJz#L)uZkBRLEO9b7U<&IAHYz9ABzg)@m0OZY)r~{12py(r(e#=zZJ9P~OOG zGYdY@Kv_^%gzjGdi?fFPbb~rPT|xfVQ;Ark0E!`<1rZbFD%0Md{{+i#?c&l@ak|w_ zn`mGnOFg}TIh|0wy|e4hZoQ`4`^4&c@B$fIIeatBO?=)`Pikd07D(@jEVbZ78K2dx zWi-CvO#Z?>WV^)_V0Sc%=L57}Vq`Q7)wx`g;@k7_@W0K=u-g>(!)gtQ`GN)1J^#BJun64z0Fijud3)PXJJ{(xIyY zxqV7eEPk*J-sO@yR0b4F6i1huZ)5}MP)B%Uyg(t1{lVS3>>)q~#DP}=c~v9EycRKE za5**VesNwPh*yebv6IXd6A~c&YLU|O!qvq(gQ!oBB#eK&OjW#RWw`gVIH~yNMrLi2 z9?zn+908&xe)T|Gm-Zj1Q$5*qGdEko)O=-b&0$S?R9UDSuPDRIPUMv9R(3IVHP3 zi@>g-NrDMACA}$AMgR6c8~Le{qj~04nI!}yKriV?T_z;un-w;ymIq+C$?Sz17WOwT zVhCpOmQ~C1(tv|82nfEUeXX+<+;IB6HF;+@3(ZPuMv86!I&o`DvN>C`paru3v>rAGqfarL&az zEano-wo6>L_FHNdxFNhNY_pB&A`K*$8GfvTzj0Pf-np%vDHJ^}#9u8lpet4RSV;xU>LV30!ng-`n9$)0F5`gKXWS?{zx zwWSf$i19fT@+t=ay=-bBr*Z7zSW^MpaeJ8g-d@_;z{{y(^xmYSYuX=|1*RJA+?qPJ zfYB05E}FP3XFZEFUer^V`e1Rcp`P$}LG1jz#&I~9h;K4vCrFJ2*ZuMDhWq%`;okia&<5P9q*Wq#cJa zFln=?e%c8JVwz>u6*)F2IDS=zL2cS+>n^i6C#$#D@$ZqnjPrUU=jR{)55S8FH2%A9 zbeDb!1^$VB9*nDIF31H=ls1X0R#Ywva=n(dkIe*e&%;?*v`Sz7`X4;UfJXkf zm#|Qwarn$h3*lTuivo=PqNLjZ?YbOFOrZWpX2}>LWfa@_$>pYisF&4kjXFL)&Avysp8lKy@7C!Kfh6YyE&(Auj7IQK!w3w? z2VLJ6b-&1C4$6qL!&-|n<0Rd+qa&P0DQ7mHAagL(I4%Z?t_p0EipZ6XRbziNRM|Fs zB}@}o!|N#92Jy1dq=*@=Dtt5;{#G`Mwek}VK$BX>8d{X`#@wdP<66-4GNYTfNR?^{ zN#hu!{VU^GGbC&4ZN4nbslxtuRJn2Abg@Eyh*t-O7M=z73{M?4oAV`|Yo{C9C}tZC z)=d&Ym{}B%pnG-uy?H2#vsURHbYqC!q*-XfPvNv+<10Y5dPU*1Erh5Rv}^3r+60_9 zh*K?twbs?eqoi9-PhsBaoQ(t?`I<#F1DJDIVC5RT#eeG38RE1j7MDExpzbrGUwnn4 z86;Gl)g0q)fa92BOkDglsO}ZoRPY2PU|b{*BT;3Kc|PH8(_5{}!$0?YuXSr%VGox7 z$7OVbY_M<&D?YYR&z<@*6IW5bMeqPI>+=V>K|1DMslgZ4v=gORNjASA&JC_jv=lv?aaIiyK zPpzFn(>#X_`K9(A+Vl?Rbvzq|r$;L4qz$%O@P#WOa&nXt)aG+Ig$A+g1;+0yFnR+C zNb##4wr~V3ZwS|>ltFQL#DQy`#JmN9pQAcPVCY<%XA|g$iAxX!fRN#ehr^fSquX!m z5^t+hHgO33sIjyX6f?s4h>GW(djl1~YB_k=RN&8C)H+z`%MxV{yPV5)(@4GzobiU3 z=ejKJdc=r0cp$MIlyXw}ftFimMcs-6F9jn2PR;w6-bRep;a_WvK)_hGIER}Bs~tB+ z`8As?!vV#{f)-`eqy9?A;;7@8cHf6};Ym#%?Fu-i-v@9UK)MC@`S42dsClgXu=>E= zw@efN9G2fXv#>-PjJc>7n08c44Mtq^xkKXxe0ljxGQ|i);O?p>dDZi392&Ic$_PSD z+59zXa{i*dF#Mk#@z}gbnAV58zfJF#9+C36wTK)a6ZUavAEB6=l_%*~+H2WyXx4pT z+5~21g_=LtL>L?7#X@>_M~3qT^$k}d`qEW0#f|Dx~y<>nx?io<1g-f;9x^tBy~=nkS;VT5KM&|j**DZHP1`x z=1mkiDrZ}*?w$#WR648Bbkr6OsOEz=e;CGnS@CUfHu`laNM2fqqvipaCJ6SFF!fP+ z@EK({W5bo+ux>S_2RKuM4GGGyKfsa|DoDNxuXP)B&0oL%-(wclzQ;U=;L>^Pfj1ib)5Afa%MI~DL7m+w*LSZ_jAEij zcr0Ppm(mQ&QD>YG_uiBq#2r}bhK%n=D6O_FhtK4Fk0f9b8>#4#4EUSBVt7E&&&&0v z1(81k7+!ilPWZukv)#+YDS%G$gBC4;)U1m?Ah}-HCSm%ga8tCu@7Y}#ozhYxKLCydh@&m z?c>0w21m`NQkQwsoUqbZdu9&bk-a!=o;JTQF5j*fQHc06j4;rZ+AE>?>a<=kusg*+ z?YdWpVMpe8ag*;w>-d+KMMjOmzTZ{VB{)w{LOWTQZjUJtrumh5uoTI>Mi$zxcFiHp z-o(Kptov=BWRe-=TF2*0N)C1qeY9FwgoKzKuRK)IXB8yw`6`W7DXh;8s3*6z`eyey zbl1gx2|dmoXsBNdUqh~!HAN_m(e;2k$0TAZ9sxDU5F;&lwpIqc<;Xu1GkBM|q0)K6 z@FR%!wa12DCn?|WV4Q*R7wYeFXk#v*d zQNhmZgp-lfsz6zu2>|S~#NT-|`0Gc|zwgFCH6<=^7NZKYPWz?=E>$f|^cWva6@3r| z!cXXKqzIVQ9n0>3x6iTN>VX*TTXN|@<%5YBE`-&If#NO!mXLc3Co=wi^7Og7yuu1e!NI-6} zy7ro=Kjk(s*yz-zBzbV2z_T6%cL>Kr_tLHrq2#gI(5UGVP2TRnG~o9lXHT`3c&64^ zGFIxqd}eU4vGprR)_`v@Z&sIx059e#Jft-4@+U(kP1)D*ya{tD;+TE?dmk9sI+yBq z0s#-9(ULzkJt4LgSB9tlM*RrM&9ymVb!?B=;!`S1j2F=67OsUJSb;WI@ARCg<}OIJ zLUHei&I3z>h9O$qENpp=>{g-jl?8PI@r8AI$H#Ve>MiH3JM|lOjuQCK{#ll3zx9yv z@hNhFTmsWdF~YQ9A55v;Kf~mYJzNU#t1=-StQgs#Z_|06L5Y%@pOs8_ow+PgvoP^gaOF&K--3DRBF0cM6Dpy3z?%9Uf@ z{Or(QWbGF(r^Yo=p(p8^X+_AsUnYKM)D1`(&37^9mV^*;KooH@WR}{otmy3jBPHPd z^l&<9(&GM9ms=g<5vseCX7$|!iCY57*v|i>U3^Na9p!wF^Dc3Xw{qq4pQ8vHDKMVK zQLkpl-a9M3$@pWyx+&T}j<4qBo6BbIe95BLsY#5LrE}N&@=nDzdiu@oDImc{wt#>O z*$nATmFJ$&msArVZS6$m{03yNzpx?)C7~a~`!5|I?5ei~ug`bft#ah8_khf6tpdRt zMF&kwYlU<&%A7DG@Y%#;YcJUit$MERbD@Jd^?t05mGZ0oF6ikc|olt(?Q2&2M-$FZrp6P z6>FQOM02(TdmRam9hfh+WFoEc?-yiy!Hu-?VnG8sI6lipL_|{^;z;*6>|>*3#LmM7qk&W?w(4f6Vxnw{VX3ehw5yPH0#a*EWP8IavEN5RPQkcZi1E;z znl65#X*ysb&89^D8Kn(0g|JTYms#e=005Y^Rk<_>ofNjoE>dZC)mb)&$V43p^C<33{;}IX~E#F$Ln8 zxo8dFEW?u9erCOJv{HwNZ<0-N} zvt0_atvsjXDWVKqqX=&MK1$>_M^m|%+WT*rXy3i#o))R;#P~>O+8h)NK`PQ4b{W@G zxMs)iCsx;nR9`=XjppuFT$7U;YV-=g6XPScz`OVdox0)t5IWbDE)8985Xut>G02t5 zxemh8-{9QJU6ia3#6x$8qwYw=>&*z-52uM*B^Q^FO%o*fwcd=w~E$4Hj!!>QZtqq0iQno5dAU*y3hUcg+F+|E|E-t_WB&zL(N|YrFHlt8) z5A1%9ezfZmLb*vQg-GO3pyoAS=N!R;8Kv+fBwATL)lC7tqdn8k#>nWoDTs5#mIRRY<%7n`-qx;24+AM zK5IvoV4w6WsRr)@4rnG6#0W6D-0L0A_0UF zWBT0V)mIYqs*VzvWFdtUHmXeEgyw|qhFciHl^pbg6sjizqOUR$kn$@%?@T%RFjPGh z;=1NG)szF=^UW2q(SX4`X4Orl&9}dhgMX2Jo9pb952Nl(8roDa!u*-7cvy2s!4|%{IoLkgt7z`ZKfa}p z6BiIpP&>2>wqKOnrF3_-#H6(pmk%>46}W9coztQ`z`AaD!d&M@e|<1N4(AdM`Z{Te zmF6y2tH^f2s=H}Gm^WEYCs84bfv-DMf&qzotH0I&JmOwQSYIvg-RfuVZ)7`ux)FBo z^yuxEJKOh+%oKS(y8Ao5(;@THHId`%02JHUMpWU+7zRLLw@t-L=yhS@;9J5fC!vJ| z;~2ld&r3}3a`t)dw+|h0N8-hxsQla7ZRX@Bo%vQ=Nh+lc2fn8_tA@wI!$w!1Se49$ zHWV!N5rXRBSSw!dopnO-j1|Tt>~2j)Ir8`s8AJsiuZQ}N7WH&RV;aC6g1G)R)P?h+ zmUCv*8^h^?3rm+sbmf6uORc5`5;s2EU1DLb4S%<%^Gp z+QSW%Mu3Ntbhc%OL-0C&Qoc&dR1{36aik6W_ZqV|x^+Vwv;w8Cf>JEvW_ZF|e65(l8%r>#9egqhwk-WJ%J zOUqqtdciX@T@A^i{dSCm4J>!hSnOeNb7;^FC(NzEtwnkhhNMT`7gGUsl4eT;x4LG% z`oMl5q_f}J9U!$ks$D>uL7a@{14IcD;)$UuxeweBkPB=;5)G6mKWGhQZf zSh|=$5}a!>d(1ZRx8rhQ!h}54stTy(|M$-x_$OT70u`WirFcHBPnk*K{`HJJ=k#gj zz2}4sJefSS`Pqg64gmqiBlRXPGKw=3vT+9a5X_gVzx?O1>e5WVq!!pKrel__lFi(* zo`1jBHC4)v<377! zk8BCuo(-uBbIle8^I+BFsbq4S7S}yW9T#D)|xDv(+EX9VhvC zkL|nJb>N;N5^Ua_{?OjMVI}BKBZNC!J+_O+kDHQ9Sgz;YJfpUyV1bmKA6J}K9?=f< z*2yC&#rM<6b|{1zN!*tU{uuoMGH&*wGKPcm|Ik1u$;U7eT2M9-BkRC(S z*i_X^r+9b4Zg1!rC5L7 zO12tIhtcD_H?Ns5JhP^*8if{%XSqLxgGy`=ts5$=y)$|C3{*Tfdnim!noT2EL1H1XP4}I>g~ULC_Y7p{n%_1G>_1A`A?k(h{8r^~7m#AzoGxaKC^etHf&vkK5~Zej$C4-Mh!W|pu&#%Aq`)?ewDo~i z4VJBrjgCctd>ycT^zVYM9u+HMG%70FbGp@IHL}~F9Uj!R9KEq^2S#Y7CNh3rTsDWi z-1?hesrZ@jd~7SyP-NHD4_8HJ-Pv0B7V+2SwB%1 zNd7IEMa(_iwx%03enF@gAtLM4ZRMjgk9<$jQ>u>R!K#~Cc70J7G2v2s<|p);TKs34 zBM>KxreDD_Vbr<8I*FlqF(BFr+%1(z^4k_}F_U=hsRtUjTwiw_F^tXh5SN9i-~z|v zzxp&EP~c}$NT;-!F=1k)IlxAkCiIVr9-H)9Fo+FyUqO)E2n*)Di649k!WE9X*@`Bh zs!YbcVU>+GTQ*?b^K3GWSg;~V6l!TELBm>Wb~~N==?}8_Sy#`;d`)7t^AG1rjagTA z7ElC!k*kb*YJy|h>n=x@DIAwxBHLSt#yFJy65oXl6oXXv^-dz*9`768URIc_Fhq>{ zN^s$*eWa%jWFgm$9Fmd^FS#&Pi$OTc#wc|`lDCX;-%%bZFd&_L(kJ;nvWp|&b^9nh?gRo(l$@sa<(M4&oVUEe7F!G&McC*#eE`1rj5rUmZ*99nr9H>@s-!#cJhAsT znQZi2l%&Uh{yj$L`|-=lmx43!LdYhrIcX!KV-XK&#L|%iJ*3Sng2nqdCt7mj+#BH_ zuxU1!r}aWvK`jrC#tbP2lnF#hl^B)^bPT&Rb7AQF#Ag=^-9C+OTxN1ZO>>1#=4@a^`8NteMo#uLah5`>rr9q8~VitP3_mhXUl1A9UGBE>ttrTAUP?V!=sF?Tyu;!7U#9@P9_%*NltX(vjxw#a$7rUox4JE~H zNXTDc>%p1#PYs^jVN43%B$tnzS>YLigu*H@Q8-*X9ch;CN6AJzawN-kNA1_vDUXSS zcc}*lL*JjWNK-mZzfq9_IHF@zv|Ho};^EQv^%MgT!q>ZCwIa4H%E(12MPB0t>X{&% zUhw~y%hxC${X9P2{*)2mX$H_a3P%X@^1P`vm=LQsA9SS34ziMw%zG}^!x5i?yc#u@ zHtasz7tqOVF#!}k^FpHkcOwnE#{N%Z zk;qq$5L&O!eHWL$(K|64sCATJ_^Jjuw^+})A)!l6QM0ps@22W*FU5oG(6#mCc`Rs+ z+{V4_y(vn#^NViK)5i_3($jX3k6LAZcDUIJ>?oh8o~j{j66{Alir{UFqB^w6B( zk`T$6fR6i#p7L~>m#_ZSE%HelXzMQKYT3$7LCW3eDO<4k&K3mn!zeDa3%3q8qy9}?10(g| zxR3f(B;FmUfJ0r%s>@x7WshT|eIsq2KKS4MZSG*+2=%AmlTL6Ypl-4T-=4iqTRDPG z_P)zi*DZHbjGSV&r79fNXHI1c>zDdsm{kkUbx73|;&?3uwkx&_&t{w>OyVAIsiX+-D5h)sd72av8b9Yk6NTpuX?TKM`7}7C#Pg z72V|}y)HXthH_9vr8$1v(sxXpiI>h;jOfCcX=b!2V>344)tN;{)%}@qw)ZB$6WktF zYiGvi5fQ$h5{+mRF)#kx)6Bojdm%ee15pry8I41R*L|lCU|33i0 z(+5c4{`&KLspa|{MTm6H0@$ZgB#j7nw(X{clu!e)bG4Xo{n_FqatTAfj!QM_umO)b zaAx|*s35MMC>YLDl6;AdtUms31=2zR)R?9;Xg%@twRw-WGg&cq)zMous0?4w$C27K7%9 zimH`@V%Goqhn8;4#49+dX;(ti6P0C4&$}O_n-e=ImT*2g*7~1?;a4#!niT5 zwfOx<%Vml!S4UBD9pA@L!A$f`zF{@{BkP!w|y znaAs*B?PV|$g+;`x3E+Zi)*s>*jbJa?~MD3qvS|h4HA=0o)VD}vdl|oWSFR^g#q_` zkyfXqRQ-ouiK0=VuuJ$`-xJAJ|75lOue289kqsh-8E@FVbiBR_=IW~(|9G!7`%2Hx z@Xm;0JsGXJQiHrIOB7j}l z4!O2NzD|1-ssEQ3M-S8CrA!t=2&=)mXHd=s3l0H z+@gQLJxkgYoKq&5QogQ;+Ef|o0SnhSUv8V@P?&L*$Z<^d4QO$h#J983omV0l{Yn=i z;xv}LHxLTaZx_OnJ3&WK75fdA97vuUpmkc}1qP@995D_v8eElDzFjr&!S!_4&|geC zGKD&`Oz!|^wq5ErfsJAStGv33nr%eoexgRH5R?jmKN124VF=X^CK zgUIOGh6Efheyc-YSVJa-^*{p7>?wloW?@)>q|1#+vrMKw?uloh;ULMs&P@C#86w(t zgv=0`x*b$JpciE1gVRI6JI7)c3Iw-Yr4j>7Hzo< z9uxr9M+Chbs;V*U$B^G_ftO=6FA6sSQ5>|7yH^tsb}EneejMEqxNl~ug1>hDLu^vX zlGi@UY^2`?Trx1%B-*T9*sr0X8=jAQfVn0hE!~ z0#Z{CZY06-#VC0Q>mm2ayqQj&ewyiQq6l9Vc3*xX4>X6ZnIVDdk^m93wHWEES(=UHyVsmcShMo=@e@iv>Wny)c`a@wIG7BylUeImvc_|^@?+2kjI_8cwD z4k9WV^Q&m|%rE+VaYy2tT81kv8Ffgeq*ma4D+y57oJyHPDiz&^li^h|-@MsT9Ylq( z%*Ch^k-ae@w&rjLMBq;Ah(PveO-$N7c}vJi|KTpj_Jzyfi^4VsiR%jEW#gC4cUIK<9pPsXdwjCp}pw6 zZ?B^@!!gmoN%rcB*ak16I0StWbad(mrLNw-`Zz7UCU_`;ysJm-v^F2~)<~IW>2`eg z^nF$PrG@>o0y$ueS;gz0{s&8sdn*ha*46hH4RUr5(?JPWyhi~^8Mkk`&$nVeUP=`Z z%V-Y}EXoH%+m+Sm%PA7vg91W6Oj4x$q;#VIpXSD2t@4*TQky5|oPSOkYPrf|tR%ui zB?HtslY!T0d5Mn4<4`X@EzRYgOmC*lFc4?&g+5&4MzyG$epWZEyEcbn_F%KayUG9~ zNm5eI>MsjD-ouRlSgkF@6U2Kk6BhfyRxvjFU?8FqB487wg9eQ}6qAE~{l?2fo^ocvr&Y zW70HH?lWTZ8?Op=IAfJEu0b{1elR5==&ESrQbs#3L+o&g?V0dDnEj_#98Y!jnV5S% z-Q&Fq@t0pCU{WSo4BknfooD)Pdt=&xxscgnjaD@C#+NTDjH(x$x*k@0|79T`B0ikD zI-S`3hC_P|==t1X$YW;~jWpbCZFh&ZJZ~HV^W8XvWVPO1BJd`2bPa;DL9X*;8asno z8w)Dqm2erq=kY`tAnHX5`hXQCU;PZhcMRLfc?#Vnq$7037ZIg>G{F_&GfRz^ti{v- z5Y;&8#`CF*EUImRq}5D0uX`YZ%4vkQ4kYt~8~aZ#eTny2^JlvMKeq>s9vXd5@QE%2 zSE=+}!st}1*N&T)$~;xCJS40?)E>BNRu^q2q?91m1G{QH)*ud3I>spBE zVGRoTArK9foY0Uw8n^~|Zn7w5XkQ`_be|o*|CAm;^FY@f^rS5k$s2h8z|_3Mdv{Nm zwIevZqU|Qj444>0BQ?QOl{(kEt5Nbe>h>B~iIBYuik{?MT?fj^OPUawQNQi_7fVlkjI(bAL%kZeO zbKh~0pBia&XDzVy0pJyb6Z|D@E!NzjI<`K#6g$Y{)Y4|O(LN3p#z?pk!C~A)@rxYn zP~zN`Dx_`Ro{(`kmT#F0DuIm_wjto0mKPa|$htU?5}ZvC_SQZ&cSd$mjusz>zRoG^ zIm4@b`=+e2CQ9enf3H2Zb|}0k9hn6JDtLsHde=S&$@Xf zLN1AdkOn;>^>6*&Y~8Dwh%QogBLDZbK*kB+--c7aoQUWt0 zmHytte$(LuR2{n?f&eHiYcd+}iDceB{grrb;qAl&GnBv)$yj~SonrTZzL3E0Pb#}c z(F3d+tOA0?9R|<+*0TjPpG6{KW3SzXoH#!Ew`c+NML{3@_ZBw<7oGueVy6=5N^|Na zEUm6I#KT6qP&^H`07=cZj-aJui`SjG?$r(PZVDXVPvmB3onUz6WSky*5sYRA$}h8n zV>aIyQJ~mwHBvx*m67{nn7zhadLgSfXqn&R^PHj1h5>%JGLruA~v(VaX>v)1~$=np|UY~6Wm8KDhcdFGEx2q9plp-b&X zEH6VYA1z3Rm^%Fnu->tZV_dZAuUq{=#Sd&sIOP1GIzI;!{Rdi2??X*a|Bzo^wPwpI z#1S?rtQq2TTzGAdwzW((BU_EL%Yf2sTqN!+_ks{jPoPWjG%uh-&CJW0BF0kfnq{W; zt|6}OL3fD~N@n?Ll>racZ#{^8*b`1qMI*xKDHzIk12(c|+A|`wLRaE9MMf?Y0n}?D zx$)PT(4T?$-@b$8PV_E|!86D~Kh0!e=`Nu2MJ^(A0>d}GU`cXM4t*z;&koiJS6=PN zDV8wVn9C<5piR{Gz_E%2TK0^2!Fu3e5nzl`LbF8Pt&2y?x&AyJPIcyl=uX7bLHSP_ z@X4qXKC_PJKMtf4y}}Emn1Q?I$@Hl{xvGi!3OQIp(c2P{g_^8UEs?big%Cl!C{>*>3AW4imytXtK!z26$AJ>Te|EHCK(&AF#^|QB- zeKrlHhnO`Ol<>q8A^_7EpUE(U8#8Kzt7oLNBMQ8b8qjqBGL}ww4k>XOe)QT3!V1az zXY=9h&_%!;Q*>shL9lI&- zjNiElm7soIkRc4)RWr{mV&+kF5?cw9>>|FZZ`PZy94IMe46r}1vjSDkhxNtq>B7L&Rpz&v!Q%#kCgiY8Y1KWL|yJ|G@GlP17sOjp;g4{o8)@(Br zS9IXS5YadI=%MC5``5{ejvSgQw%3*$PC$7`o&K?J*N0lazjZUlnuB!zouFv(^8|Jp z)FB`}v}@@OLtE|9D_14NkJEpEkW`s0#~1i7Sjo+~l4IvzNrjYoHE9}2!W5C=Ic}aI zRFXMXWJ&>v{=};O>|MDUKVsdf@#6mDl|y1@@Dr3K#3GA{A3%lZ5EblXRf*F0J1=qG zhf|&QD!Hv2MF8m20lr74{0Ihah=0Z=`KV7*ugAP3d^|HvF@H^ii2ppJww%2|3PInp z?g+-$(=|2Sueyx7+fzET3Y({Z(>KcaDJY!no~o9mPxbjseKvwRS4D#Id{ZQs5`pZH zSy+!mbpd9~n?R9$&O@BOIYY_h3gl;CVLN5Bcy$iKGs#h|wd;CPjP8mtny) zOODqqH;w9CTM(}&uP&gl4ptR9f6ZWNUcK7tUW|SaW77mq*M+ltudSRuK4*sy_~{)- zEteNaUGIJ=EsCI-3_1DOfwz2QEwk1b@YICl)hYLmwwoiZQuS4wQci8&goRfxaeCBeuP&Lj)yoM)j5!A*K!WX&pa<+zNnX@Ad$cEHVCPv397DDeq*u(>?p=nhT}vb7GAx{0PfrnV z5-(u+1z3eC8ycE1kU+<}tE=7FyYI$8Qtm0pMddrZqlgB9_i};5@Q6MW92X9--T|}m z-+dvuzzb)~A$17;j+r9NY@c92b(4gc$X>e!wMGlw*9W*^EVX=!^tHf%R}9q^qs%|> zTE#l9SOBGfwM((iR_nR2AS`*<%`K5=3Yt)4qNH22UMKf&8E(qw7IW1EDvA_jhb-kN zj`BMbvQkD}mI1xRBcn{f+Gt*p{jw{)amvGPeCGlMcz~h3y^1BQM0svD;PooO zdx(5GNz=WaPMhENVpO?JYfvU8_!ir$C`M!BfEb_sELA^gZE{HGQQ(N|jD?(Tz5mLt z)V^|ziEZA6zxlb~&yI$IDW9Su>H3gG&8VVb-_)X+VB~Owbm!z0U=lbloDfZpi5#3- zwFA{$SHPO&V!}tGjpPeX=~j|_YrbSHQM`B}>&U$&{1R<(#7li@VSTN*5k0qLoBSnX*tZ9^pMxxdV=xTd}nSC_A`|piNYK ze-?&Ig&1EjRs}ktwcvwe_)iXp%HuS}7_;Bk|B6uGC)>GvqDSn|L2bp-h>eg1)m+*G z`A8(R$Ml1CT&nPEkPPh)mHtl838H*aFH9h_A3#7)Zez>6-m>@ewU1EsaUhe0@G^XZ2fP{A<{s9`wtCPG6AI8{=U__ce7$mlp^Pamp1W zsZuVDoO8n*5|;e>#XcPRAuqT|JJ~;Y@-KSq8oOoo0AS=R|2pY@q_|GC;u{y9#7o}X zKEL>kp3F_$gy*E5TjA`s)$PaO0_-nNR8$VcGA4I_`gW(_eJ67EAv?n?R!safW|t z3hP*hmi$kHQHDVUrYz?B>MLrWK3x+S2vpm3pJ*`e!s!u&mbk7;Ne=M3jtbJ8n72j+M*1 zP|fbpBjzX^xn?TED4j*FQk?GRe3KdB{>F~|m3#1x)~tl&|DcA>?C^XH4xgS~Mr=eq z_kXZz_m&xj`<@>UUyD{JCZ}3C6JgSFE36ztbcq$B1j8*(XXt>E=8;w=3E0 zstZJi3vL7C!3mXZ%C2DJk~Ys4!2bU=hEz=cYTGVVdHs(4svA6|J?1hNAJEEHxw-1# zn2yP38+Gon@o0{hoYJ-K9^R_45@7}BD3@3+fpGycW56}&7LPr9PgIn2q~m>jAYdAr zneF=`wn*9Y+|JaH<0t3v9@YjK045dFBq<2q8B>OE0~`pZZsT1Be($Zs;z=))aS|Ht zI-C3Q*X=%qrG3RXr^y$&`1xAY0#k2$!vrOueQ3Z_NRQ&e+MNg{QQX5!`5Ox?>`_0- zuv!wXd6jIK>@+jWBs>9AZ=AlecKvHkaA}IX(t5N$F3}&&ElZm8ou_lwF`;}mj{zZJ zn=ovp%SIuSL5M#m~;(|B5z<9JThRO6F~D}1Gs z3%au`J8%4DVJR3z0x{wMx1)}y`uJ@A*G_B5mJ!Hf!LuEQ#lC>TQ#l>A9yu}OyK0XSzO!Amwq!3u@#owz;z`Tfj`0VZkzEg z^_Ye-2VVEtnVs$ZI`5857XKw^yhhuQA_NUprv=;E5=_k-2&V*x^IeqGXE#-xt&@3+ zugJDasKFa*=k&D_c-G2|L6G1#v`E^j+UDh1k!3R`EYs|n!Q4ZzvRFIE@yNowJnM#? z9QMk>YvTagYm_aWtE_5nEy;-6o1>Rt*Uh8md$maqK?451c6BhvsH&7Moj2PMVGLuL z4n$T1YRH~8Hb(JpaZSFbHW=`Q+Kp0$sgF;5avR9^G+s|!4EfY9sG=-Id-}8-L{5ATi{G+=; z_dMw!1|6Y|)PF;sW!-a2K(9<`>&MMscFe!YTa;qG?BoCcCr2fU%E$B{17B{PFncwM z8Uu8KSk8W~PSh!1M#rsMJzsVEe7avoX=#9~@CG_x z4kQ3MdEfG4=B$!UvIeI@g}iVkskf<=Uo62#6iA)S@p*w`Ee*KbgzU$rYhn@<&WH}- zwL)37-;p2FP~N1^JYe5U?lW3VtS>Zx?QQ1Z2s_Z72l7yF(G;TwpKn^%3B&waz8f7c-ne zv5D!wpl%H!A0LmsHKN6s|7^NZwLBYJ>yHT@7%&^xjQ%k}qMH`#eVKwUN&*hd9o_>c z?e74%+LM~zVBq%uFSU6Y9}T)Mx^Id~$x@a$9)uxot*Rzhm?Au_#`nkvQ@sNe0}5^E zujxM)JvbVNs3mx@o7J5&J|nufnMeY?0#_=>l38C+tx`w<9-_iB;c-bEeL2=ZC1=6b z=j#_iLPx?(+Y1~A3NzLf(P`_P$9nMKcRuWSE4reb(gEMB6(tAYVhCn0{Sz7yfSu9Q z5z#OoUXEFWS<2Cg!K0N{?RuyoTf;RU{U12UEq3BD3}QnNK@Df~aQXI8`WL*|)hs^( zvwBI4%cu4g5C+SXq{N4?+1KtwkK!Sq!2W%T4rc+{-v&$L^HXfZ{N-<#Uetgzf(2VS z@s&-c#47!4YPq^t>iUH-B=Dxy$Y_-Db*LRJ9rs6|t@1Yh68}O!W{VKa+`7$`xDuy7*O& z!k@<8;ZVL)Sr?m=tWV;*o;432As&|0A{(p@1!aEt`lBkiXpc#a;fSFj$2!PhI!G>LuqyOrtdS^VMmb$VI-$U&)w5pMKr zi28gsQmEm!uaO+s{{C#^zjR}OMy?e^^cp3xgU)IGukC_zy55QH;kQmZK}$3kQR9v; zFM8xvX$PMS>p5!@(p3|ZkDL9M3VO8Whyr3mV|B$-EsxE8h?d-NwEp$E*1>fqOJqUN zg9Nyg#ED7q3UkfqSXvJ>xZNcI)fJ)cW- z3-arDNPc4;2+uPq_%81FV=OCk-0r1N<~+wN7m&j6RBt2)E@g!#0%LnN6^OhR!7WvP zi-y2oW<=i0Xy(T6B5CBf%H}PRJ1!h8ZWPCa@>yU;RDF;0-19~+mK-QNX|iqLrYY&! zJrXz@la#ywf*TJ!?5=EnpCp(9p4)?EifTyBJ3Vkg>oODY`3lqZZlCUa3n>bMMpR=S z4AYm{?XPqeHFR!Xt!f}6^mN0s8Y_NUwaE4`PQ?jQ=At7o{G2pfd7?uXGTAxDf|?iO z$YTT9yQc_y=Ni1b3;ALX?j&G%e=kp;>UM@Jy zWxwaWea)fB@DVr!n0MpdN(%kGBW}OYay4Mlwp8*tfFI#+5CT~5-&XOLW|J3 zVr0~fD*v?feLssBcJu{oq znjYxiz=uBz(RF}2pSm2s_g0wDt86Z(2p;l8K9D?!$Dx6|Q%3ch1RRA$Ao3pGYeXbZ z0gZ>a+n0*YOMBmmI2SvY40=$D@)*!(ZHhccB(GkyFa#DQO*su; zb8?WF3PUpZ{>8v-kb&JkmCgC~;>hBP$RJ^5K-e$iWzcfX^vz~CEUmx*9*+=%<&(L0Qp~j!oEez9VTk!`p^ROV90LF?ppeDI9Kl&5 z=o*@^V&yh+1mZx~vxr-vba>MQYFCSd9!@7lX^GQvAnLwvc}8&|ncz1s;hck&Z=Ro% zj&P?E%o!=;79}&%)3I_oYFUSK3-#A}C!WGXZHEmN@G@;&KBi10;ZodF={=3NbR3wk zG+kiQC`ri4T^rnVWme$|C&hESbSgRy>;HFm8#BoS6rU zDLjKjoF|vd2x9ZU!bT9EIe%=003f-Zoh2zBeeXPf*c2PMh)(#>Q1gH9PfK6OuU4u_ zP{^R|1$rs%%be$GKf&a70d(AkbSkNR%=R~T5#1#Pq9FN-w==@dlcV{Yfz%XEUS5Z` z!nv6InDg8biCc1Bu1aM!7qdrYu~AWEjH^1^Pz^+K0TK*)ad0P5>faW*d+{hs!rd&< zL$r|sW1Zlb(?|x#XX#goO?iwkfHcWynC1hoPRDFu)6RPZa6fk655R6#dIkA+ye>gR z7~Z83k`9@onU5_Y1M9aHGdhj@Jbr}*)UYlnGgIao*kYwp9=+a>%Y}RSOkTit>dhR-}4RU-tA(i!}qQU&i$2 z-z&y>sWURn_c7EUHtazW*@LgMoc_!-QCb2r`zJp;HKcJNT@Lted_4fUmw-n?qEA=9 zL___KLZ&wTeQD51#oZHhV}toXV2^p5H|&oF;2*eAG)YTd0w3^|mns}_!fhGGkXgc_ zKb9huyIX)AwHsb{Qq(#xO`nOlF|)hq^clr!v)PO?vH=t_@7V+%q6ek9sC$V6t8%}+ z(Op2a<-C`L>S)bk)Ocs7$v)ke19W>_`H7Fcf>+On_$;ecux}Ym2ibBVz9qtHyVfUh zc8Hd27ruw{=Zk1q;X|fvtNJlL73{P)JL)jbAXC~l+=2TYPtT1KEoj;#qHCNgOf-uV z@M!Z?47{*rg;MzVzqf(p?<%aqb7d1%JP!Zck>Wqy)|RU4;Dq6<^V-pZN4*0_a>Y#u z-%r?41%yk$`u-pzid!8Cg}@4Gd{#l7XhzzF2*#I%_AOT_I!S!7gdGxUjnW&7yHx>A z`&oUQjKT*nOo&7d$p9^%Ag66sOU@Sj3pv-319f_H z2vfk{l$`gOk{|&WjwdB;e@i^qJrX5<&zA4<93A zPEl33?+h94QnX5ZCq&1H^QRnrE+LAADNT_WS;ZW=o;Ivs>p`Dv5+O_^cl{$O&b<02 z#6$OK21&6grZQav_bbLee9+ctV8i*YWLU)qtzm+=VDxd2V$Z$NfD@8I&v&j{>LT9br;OKjXD;RC zZ;UX>`;xOwkrsygdC!o!z$$(>tQ0}<5*aznpQ{!ueTrG~5lp&tZlF7U>8s|oyRM(p zA^)moTK~WDh)Q}GGM^FYG>6X}r7ARW;ILCqZXkNK(-?cEV9arh@Bbl6Y7QzFc!9_< zy-LI6XOC2%XCBd3pI$MsQME%U=Xn_(Ibtj9)BOq{+wsc#;(B39;d@W){gf`nE|iu3&4VYdI0W7_*{dajA*Y- z!^T6o%HsmWxd%EeGQDsApB3i!Bw10F)*1gBvm*^`#^@-G;1}z(ZwD*_{%_4aNb+K< zG_mO}k+~&f{aF|=(Svq3nfmI;cJkYb8{EB=`>%Uu7m8f(!-#`e=XXeQ?DA3g^vNye zOriO=0`}SOfT=fO=h;BtzAB$*);SibQ`Ge6wUk%SIzASp!6{yVB6%%tn%6T#Xh2Lv z(`3BxR;~gm(DeIjH*Qy#CR=E-0M`}zC#Rub6xe_QP@o2h(R~PPaPJ#D7afcIk*9Gv z;yuu_CYvp77%a^3m`EW;;WyVM%$1l5y*47!P*=$q30P-=+6}NBQJZK4OMTdeRjh-e zcR=BAUX#zvdQRM4ebw6?=QfqR8{jQXEtNX13NIq#DvuaR3QqU~i0^wmF%{^EY&F1| zO}vc0zJ-MS;HOMAWhLUcv$OIDp2H>$8`ufNnlSx|0_JUkep*6)EU7GJSU+&*s_o8` z{(cH@n*_v^y5UW_43!@fzY){~p}ZbN$9q-@)yBtwr>4|c$V$CK0EQ2_=9-oUoZG{! zN2n$&XHlpp4B@?KdIwDr*kNSZa(~?^KGj7bfodsf=6zsVfDh??m06`;Lm*=`E5+U+ z?RBeKgKE4ty!rw2S|r2-_S%NjP1hfTwN3!VYfP=pu(XSGNm+|sDh@`};b07SmB zVndDrK{in2NtZb7!XJ) z1tR3l<`KtGA>lHU;NlWc;RW>p&dcWi1LtLuuDdFy10pPUd$LlMbWg#|>5aLzEz5@q zPlxM2U(p0tekOB}UE#qk8VHyoZjE4emW4oSi&t7Rs6;Q%bZ~frsV4CkZ^YdnLZof# zAJe&B=WISO{LF=+vk2m^2a6OfK$I`OsHD#GYMvBTid{^=b>P`Y8~WYC23aikp@@dW z(R)V$jG<#;pd0~=w^sr19}_VeBZ?=-W;PqlsO7GFKE^Ae-XTvvKDutH=?22V6sgU5 zJ3L595gto2G~wYW)k<6}-MlZY5hvUzVBcePl4V*YPno|6JSg%voaj<9-FCQy74kjg zVf}TusREc9`zsTYX|Gw>?6`Su)_7N#ic{qMAD|3m#h;o~q*AI7=Jc#RWP&k*^AHJq zJ}nmuf^W1oA<6+|)Zgsan8#KFSs!)UbNV1qG4Gp8L&u~#smOX*YW;YG8Zi6b z5+1+_N_LkEOAU%6?J;jLVi=C>jBs_SSSxtEg7;_a)ZtPeG3=sN)-X7kYc&)`G5)BE zRheGpv1M*N8z0nQzym0P1SE)oK0T0v%{`TbU(`!x{I2}Nl==-HhXOe%I6JcqwS5ja zqN=F$*Kr>(MbyM_Me+|JpFt-3jv3R`5*lrf2BwE`Ak3mq0)-*5*@5#P+_oq`iA2Cs zO}=xKSw<~~ZQL_w9Lrbg`lkGU4US4u4P{nN@Wlb@0HW{^1nH~vKSf4|-DjPUJeWyp zC(g}-Iw<0nAJL3zeP$7dT8hli!+l}3wB=Pug(_5N0V^EL0Wb>8jNI750IjDx>;Sg3 z{hKfOcJBMpiOgeb2dv5u(YYW)2^JIAA_8v7|4jsvx-ck#$tEU<^DLS$T3>T#hDu+-nmBV*xZek zKQ|+Jg>JiT#k|*r!F_v2y=B1wZE+P$vTCj2nIL9FA9sHO%~K%{ia0Dcu|HVx%ZJad67LDbt0h_r;c6KfQ1Iwe?0-6=fy`J z@}CyVg(R^jgB2 zkTKh)7Xl9|`LZ0FVTvJ7I|Df+9r@2n)J}}_up+@6Ta!j?Z3$Yg^gWOQ+;7dCm&BMq zg?WvSF57>DbveC$-~?LVp|W;$Ev6$E_=8_nR2Q|N9 z=5vst)p~zFPX%*ElXhritTIZK2PP*Fz2WUl(9vm zS_pHmFMY`Nk03~Wr&~ZnJf7HCoJ^m>r7b6l8OwV8E6D}y2x;=5h9*f5x1CryC(FWK zWfGxDJ>kZduRQm5j(6KdeL6!3Fm~MCn&Agj>sH|NDvp1qt@0L?-k+T53`)-7b9h6h zyabl*!&m?{Y%wRXhObyy5J-&=r#U|qouwv&UXXlTJ>wx)(Zt8rj`1^OtN58}!NZ;WdoJT&uvc(1y zwiSfg1!5SRbC~SlGl`KW8#YY#i?_05j!0tWU+w?FU&K?(WiUkrz%7?wCG?rqE7r`a z$3h<1qS)Y*0DU4%*3pl4H4gINeI+v)y! zt{~&-lCnx<@V`*RHAsT^olt&~xC;dit+na+vp2U?c_P0L4+ZCvGlh8Afal@~7r(VI zbTP;UEPA)vp_l!|4{t>ys)ROZFUdKz3n<&)ej;+YW8axKPab@g@jQ4^;s!Z|n7pdN z?xdh$b)`n{;uxatOb!X$Ax(!YVK^6s5&2(1E~4Nu)3J1NQsvddMB`cV^KG&RPRr>p z1aK~rGAPHyV-YJObZi_H6d7V@$@vRn!4`kzLP8gTO4C9pmRhGscL+ZVU}MBgy|)-3 zO}1f;5$b$44L*e=Wb}bJ!Ngv;a9lbJBkYx1<#LDBd?{}X~6$7jbgOeoF zKL~Cr(_IVKJs~kP8Obn<^3C8NzKHsz7Zt`hi~aL_q?By>DNd-Zm3j)GSp1f~c9l6p zaf=)Daq_PB0+R|f-8iT0AhDXPh`AKko{ItH=F*b-d~wd7-)SkYQ9Mz*E1dNm6g8P? zDihh+nWUk)Sk3!kzt)fiOr%LWgE&mL?yU7Mt8X710Gt;MX2%Mn_`X)QODvQ8lH};T1_xE5PX9IBTV^)yLN2!z>U9s? z&kyAVTK7ctmtxMntPg&}F0ESKh#6$rgk4&rNg@srZbzIXWXhW#H-8|-I)m%mn2i8$ zq`9SA1#L@Q^T0FHBlnRCd8%MPfMTu%aC!S)4i2yHKgib3pTVQ#HxWbV^q5a7@KvAc za@-txVb62jSk|R2_0a~vz9x9&hIpi7trGW)qwYDu4uBo9u_Fc}1r;B((Nphacy^d6oB<8^2l`iG&_Hd(R^hUg*An8@3 zTb70)=Px*xAsKYri1_$AuHjv?C`LAow8@3_tIcOG`*7EgL;!c$E=@O>ZiInjQ0g!B2i#2tb zBle2Omsb3$5{kh-4VvxP-mCn9A+@+ss=!?gDNl4G6#P-oN+RXXY>(YFt3qxfOx}cz3aMgk{+D&IJFO*+2)?obRzTUF~im+s5JH3 zOBsoUU?$s<%WwE1#fbZfJbYWJFN^(K@RoQY03kZXl&5VSG%QPxnGFY`c#gKP3 zY;Gr~u%XE1sEyp+(UwylXC|}Ny`##>?biZAh z>(jER9P{GFB2bGt|04K>RwV*8Ffb=UNGd87B!>pWKj%0*mOt{Y$Q#@Dyd zyI7R)#=!w{5#998NI@>NEfD=`)rP$uNVzJOLCL2;q?*2dQ?u-g`dKGTM9gKVj1mT$ z%yroqcOM0`XM4yGtooFKCC$zenLX`0Wp&_5-(hawItY~edymLA?M29VR%n9xU01zx zdyT8SX=iud=ASKwb4n|NSLe%CLH+)4AldXm{`qW?SPv1@jTEkNzr?^VHS zJ7PkmO`F@>w;i3E=-&YK4BiovF!O7`nTAX@UJ#dSj+xa^iO~>2ujGb{%gt92Eg>Xu z`?ql}xt5YL6=_qMZ55ZZAZApg7W$b9cc>LGSU8=V=`E!|8h^Ezr28^b{X#5S!hH_j zN(HC_KfLhpY<4R706(@wv@Jru?CHQ>lu;(`WgqwL=JQzG4-Hsw`*31)?c8s@oR^c~ zBo*qF*ky0qqQWpv>uQHXA(uGVQ{tW8frBd9#qeiR2ZC{DlrE*GR)H|H-tnocY89fA ztfn-MB_Tj(Cl25Wd?mk>9t9E;70-g3I$@K>EB}q*ZN#;Y`Ta6AP6m~Z9t0lB;kS2; z&*8t|8G4Z6!Sz3hCI@RmhZPG0+`>z!?;?TJ_1w#OfF8^Nbhmx=(*k#PccjKQfCC-8 zi_aEyI%g+^I=bQ`z~HO($mGYiK-i~Lby0sponOZUw~uZEfBMAig&~aERHRqmMdf&**O5V`$(xK*K#Utk^SVt z-F!{aa2J*;1xAhhEKL~iwE7p(dSbfKRuf)_l#i!r(yqXjP503;mt6FJ+5jy-f3>I~Hj}Ha}i^4P;8-LBY#ShCoQy zFq1T8t=?Zjow%%*JWs&U;{8$ z_z-G$r7oEasM~mD(T&4H1vXw<)rIVY^LexQ*6%v4nhUfaV0*VwK%4G03b6>hemCWap27gb;aR+ ztW2S5hxaWIlT+Y6=*~I9C^gBn-}N+w?f||By1M{J^Bmo^9hk&P*EihiQ{z6|1Yl~$LxPzVAcrl1Y3(Y&JM;tr35mH zsn1Cyk+Z&bSEI4@?RVSz5VS$W{)j5iA8#I$D=ku5dZnm7O9A{^ZT?7@Phf}d1JXVT zW>9MY|33i0*wmru1%b3GD~n2DCmdDM6&ZLY9ws?x_^x*6lMJd+YWeYu&z!?Hv-jX+ z!)$~7Jhq|pm}BQ{_o=uaM9ED05h@U%CnlcM!c_AMGuvAJ8W#x)>vAYDH{!M^rt6$p zD5Ry({-}pb+;b>7IuL!U**YD&hsP&Dbren9#=Uh@qB;YM3Il8%Ba#m1dK&540}PZI ze&X1ukQ>600e$x?iLUnoxz|kL^n^Pfmc;Xk@kAf-nkcvl7r}e#|MUu)6{T4=yrg<| zhNQ?3fhWyon~{tr@`m9tY=r`KqbZDacKZ4v5M@YF>bjg*T|YY*!zhg)&DP;QAK}_i zpH(u^V5t;gg!^`gs6zPMhpBJU=mtwkzI&FY`l~}fdf3gYcSCQ`Z6Q4cS~>Xjq1wGM znbS&uKIS@eeEoiLiE**`g@|K{mTF$;chVdgLv&<3RmIFW4MYZ*MRBP0P%JfZ6Pr|J zY@ANj;Vl>bs&|9%Lept|g*mGzhjKbv^!H6QWW;zMM74xT0O>EQGVy zJW6|u{=?jA?HI z$Z9Dkz+Kx_+oR(bzye@bS6W5-$W6j~%x_@+pYD(aW_@A8%?~ert4(6gCNmR9*uCst zl^cN$*#$im#BDt5R{Uqle8D_(EYJ&By~rf{nM44N;gO^Q@Q&j;Jf$bPTx9S};+z}F z^1uxUP?c8QiEU|7>u(+vz;S}-wZ@H`$?T0BKX(v)+YGeXwn&5_$vf~#>%L`2E z%FdAiV__3btf%2AABZTtYsjla#hlEfT_?D|W5FmL-;(E$qauJ{ZIcbS5wb;GsK z#50)3hh2atT%<{#1h${`QYsPfzEkbvA}zX(L{hUaD3L~E!d(N{&X|EV+Wf-MDCROYPx^4LtP7CDut%L1-|7KIMn8^C93&+% zsZ!C$`#8K)U9N2c3C2nUl$mNp=j^`Z+9{%uxk6 z9dzaqy-BTHT8uyBzDCXCalo-XC)?iZ@RdtS^}2rudTLqe-53*VZDl;-rurBK$%MlOrnEz;cXL>Tu~xUtsw( z@ovX%Q;J(tSI4|+o1?bm^c$n^pA#|{bMwV2q4uN#ulG_XJHbGOdjj2JVv5O7yYY3|L64-09 z+hn*Ayu=DGz#E9sxcC0Vd8^_0eHOE+t&b|_8!Su3$r-CA=L+S|h5PUlC^b88o;)0L zKF`yMNF_2}>xB#Tb06~=hLD-#3$2W}kuB$|Qi7uSr!Rua6QFE!&O&uUGgOe+wkn^}q$O~%5I$(?Iv&7&FNV?J3+&U*1BY)J zP;DX;Mm%?&RM=8M;5&n&HG8j_NxLR;9J65)kPi^$5LYh0|M8{znHYlIOZE-C7-OP# zN`CZTlGM%viE?0jVKxokT8{Y|)S*2V} zSr=TBW4`FzC44;}<>FLtBFbo=wE{k$F1w4%9%4Z$ z-sn}^zxrrS=z#P-BsLTC&pDY)YQq&!>`WNE_`IGQ1a+|6J#!hVn40I#UFPLFN759+ z5`@?JiT_6sJW5IKFVu9URP55LP{xvQ@{EpSg9-)WOb3-|N5fY7+W~~wd^!u5Fjkm? zHQ+ai|FAH5@2IAbFIW(NZ9fESaAslpQJPl86|sV?_+7PXMJR@A4tL0pb3-1?A06Ru zIT)2YZ}DP(skIjaMLUdX^M3~T5|04uOBw`uQ*mHz35gCo$`!rZOaPBnLzY7s1oc9P zZ3H5Ch}0WAev?70U=lv~*E((_w_Co%)cv)0{ZPiQu6Ih?#FUd8)Jkw7P3|1Ns!$it zwIwaQv(@I*)tF&-fnz3Vfy2Ah{)J_cfx0nkGdN*mNYol3QwA4sAz9uDU#2ek=K@Ol zaa*5J=C++oAZk&+Tfhm2GJGa#_3=K5^k(^N6}06pFEfz-Tde*(A<`1#QtZ2ZSdTfGvfy3@tY zmVPs=S_|6tD^k;bS9ko@eP#M?j5PmBZfwuxO_+qg1>5zPX zKNLmX&>PpCf2cf@sVKGi-&JSB4@Nu;3rc^mx8_QZeO1~y4_A8?r25+L|_aR*e@#xHFplK)eUDEVwLpo-XX2G9O z@?1u*ABjsMg&D8+I+F&JJoLmhagbE1d;V*cm%WF@fTNe=a9<*e;ut}^Y zkbOZt`2v~e)>SwpaIryfw61;cY^fEohel25ySj6c0N(px3e_UE`LqC{D-lvBg3Dd8u%KBhM=z*)i`l@qlec`Tuqa3UJRw}^6}aY zg0y~A`mG@$=kjpM$j_0Mk%+$nL#sF90rZaq9Bg8U%4fO7l2W#NvY$lga! z`Q;{(BU+JjK)HDAb)-^ALtwq!{4@LGC)o{CP0%IBb>;_muEi2VY$+jdYdg*8C`^kk zKSw&&9>IBxc(kmW;Q7k<={t4JxWl#4DtX$~LC{Rj*uCayW*MypQ2n7Qb~Gk!tWiE6 zg7^jz1qY>>se+@tIfZ|o80ErQ8dokYWJinUO2>sj0rLfxVwx=wrSs5)rZqp2F@|K> z@w?VWVhc-+#tEyg(~9Zjl<%mFbzhI#bX9t+$eKu1e@M9qTVWQ<_C&p?m6dl3NmjN3 z%ppK<^aUVGD&g&(<|Fq5va`x*Uk3tx!PeHpOozcVhbELYqM~s6W6b8Qu`2X9iSGZe z={ra0QS3h0kqqph2I|w9&N9qw>vN+GAAoG5G^I58Kt_-&99;&;U4{tlv2IoB?U{b- zw#*xgZT6todXo580{k-Pi;0!qMc`e%$>wF4F9FDLd8p1G41@NDwGR5F_gEBsCFG9N zQg*JXQG_jkZqV9#Ws8fEvg$zHW<^#^m;6FPcv6e#m%6YFJya+S)XMOsn-%E zmLU%VqAc7s^+q0RGh5&1EiI1YY{-OJnqoD>toIaL=NWjtgCc3B0aADM{I4pKaesY> zQ8=-hQ0cJ1^C1zKN8I5-d-F9A7M+y$fKvDz(RG%@YE$p|;+)&6NWEMDO$i)Vo2O-+ z;5NltBw7ZBsLbSsT;zf!X9!V>K`?IOg1z_9|B}#>f zLck7|z2SgX<7jv@)E`)Zgx6p~=3){9rol1g{_M>0MBske9=%hw?YacX4WV%rHKn63 zW!xB06vhK-OZ9_F+o#?`g)J5#1E*kJ+o=_)t2D+0MW#Z#wDxR@{$Y;lpdkUTp!?ck z>9J5OHt>kzz9(C(2_&H7_2Pigt*k@k%1OPHS_S_)EVjpw6mp?}1u%C3j;g(Kjw^+R zRWzPsR{(vjIkir^I6$=zFOdJ_N#mRd--BYNz$6`9enrA7=`WY=I$(0 zR1vUt;zr8?o7g9_)~&bIToQspIx^J<0UVaCL4ZhcuSQ{w@GX=@vEW*VrG1+pQq27~ zyQqUVP}N5KAu1^A$GF89V$Zv=Gg>!eWGH&oD5u`vs3iv7t{S@CSE)C5&e5ubA;mt_t^lDT3`dt%Z*vPDhMVJ_W zYtc*#2gjM6yUhEW+oLv;y54h$aP{>nAtk%xEAMoa#r=ka;X7S4)#fe+%q-sAv_$eb zo(bWpXT!gC68G!5>K?Y%CJ3TeY2;Xl_VT}D-X2Xd7vk)q20(}iLsb{la035E>ibwy zyC*#dn52(r$eo6m)dDsemnFa*s*&NExh!EfDt}}W!*rl?n5Mc3F4{{vu#|SkSaA7b zGC{e~t5Zw+cQ-4{C%7W9+1H#D+zkF)4v@xl%*{2sRt7xfO&S-+`m6ON{x217o~IenK(zCKOg;9$|LK~w)I1+YN!0G837!F@cKa8xvddb;M=IYW-7M8`(mxncE)$j zz$Wrl$ZqA?4fy9G%BmzQHG^LMg3^)oxd@@HRP)iy-JXefu4Ezs_IzEAF&He5Dsscw ze3TcV&LNx!(W-Xgen9mEi8k+1(=zbxuN0V(njdeg&7&XwNOVd{*$$%gW1r6W9H{nA z0iqloW1SiRjv2uciG6V2HWJ&IaoZbrrv^@6PxV&-v@egA@Kbl`wv_#-C!srYqO6Jj z5(a9|HG$t{%YRPoInyi#9#*yQUmxg2P&BYITQn5JLHJ{elPW!xuEHydppt|S(nt9- z53eH&3OIXs20%gE6-uTw3eRrr7%zxYqoo<@zMyA^g?}#%vrtRjqhQ6NrvaVsSmAYc z0^X5y!8=T%z-&n97#5`L;~zJ^XXZLh80=?TiIm~AJzP>v&ZFm#V$h&y8g?hV)ZZ|9 zp~rN!-e>sdgOT&c3k^9aC+IB#`)@a7v04|eErGXEK;GXqrqhyT@>bCvt?D?EfNX%V z^7M2=Y^ow)dcT^*9?V#{m&AK{p{PcoK1(GalSRizXSKwteOAFrD5~7zE;{x0?14B7 z`RNf>_Tr~l%P!eJ)#hTVD{}7v&PKVInq)?|Ii<%Wn0VnnbaS8UiMy1y?CeDw`Yk~4 zX~&p#!{D(Jb@M1In4|*$%g-jaBO4C4_Ecg20>-FE?FY{uuRhV_6AqOm3i(Z}R+XqQ zhvd8PWB`sC{%P}^M0U4)t>uh_o#O~PjUaOa4S+(xoq|P<${)9>xipWJ@k64~V$gmX z2~rGbfpypks1L+n( zFb?j(91a5&a%naSnG!?%-^)hJTfxGn_Ij%pVq0P5jNanR!A=z6PWAk*ttZaE-JOz+ znb0w+#VSVtxwpV92&B#MQ#WjdHfZG;InPWz zHaJE|Lyh{u)^}Lw32VEaN?+OX5cKIH5wRYQ*mb21$H?gWDzk#$9>G($Tdc9$MdXjh- zed!KeF^NJOMf#Wsxjk8)xi#8IVTG7d&UOdY)&aFkkY#mwe)4@xWOTM|R^-=rE~w>k z+P2efwS{zJ3{512x(hE4yw3h1@ZoK()mzm(8d`#`S(7R~S?099aW1cygzW&Qf2jhgN}s9s1aYdjueR@|E}dXqN`j9g`Pz09$sj$g(8f? zXkZLHe4c+hdyCFOZVwdyF?=d3pw`;{KSjvu7WIFcoO`riB~$~5OGEENm58(m+Zjp` z@%8^KC)dllKyhE;A44FG_b2<7A8+g2SZ$7idYu_e70Ewt{{X}$yD0k0TTV}nH}KA& zaGg3xra1TTrkW;MNj&DJ-e!75i8Q`-D3k*Nv%BN9S2t}4U(N@eXwf(jl zTl;T!al4p`vxe&W&|Cc-paj+(ISHK2y(y+=;sKr%;mh(j-*53iW0;`G!y|6kqg+59 z;MXaJ|NFT$1#!WQQR?FaU;NaJK{sPtuWBVfNh*l^BV>C_NLZ>B@mBUk^f@GyF{}9A zgTw}K09T!`X$nX0J7G|0zx>{a7&%+lt!U~n3$&HgnvQTqiceG_eV(B75u1Fd)8GwiW~xh|g%OsK z7R=edPM|JKL@`iVkhNt&sH(e=MaoP`&N1psJ+R0k#n2=;R4hc#9I^%4&+IfcDMx}h9@BV&U zkHw>tUzSo+7u9%=uMt|HOI9F{kA`kE-;iEZ%{oL@&Zm}~$j*6E#wQk`U3*+t(e>0~ z&)ZXB4H#q%vkqvzlQdB8r| zrqqWLU9(eHOjlpaV5B`{9AxlU=3Jb9h%$YGYhhE^kS7LKy|5W=SR5mxQ$i&~m=#GR zx=~VQt4VAf|F8r4rLM=0J^`3=V3be_3Y#{K6J?@1V>x5w5?w+Oj zN&Byy=&~1y5HEQ5`&qUltHB?b(Kg8G6}u-m%h>#i((8-Zpf6YiBgOohQ!k)Yt!w9q zlA`j`qH4~1n%%(Rbk;vw)%`4}EtPg&gZfG0m%ricdx_Y}{W+3RS*ML4y*p5pVUPh& z=7o6-X@njG*%?s^|G=wZEMqF1r(hs*Co=$BDg1St^G?0D;A>hG&U-h1JKZ}=tRoy_ zAH)-Y)S3W(;#p~rF*sH;s4K5;CQBX-rvMw8o&!0kyyJ=rDh52RivtJZ9oANXc6&Wz zF+BS_cFg`uC#OcOD*^*Gu2J+J>)P27`#Onp6_LOt+(824o8!7_43mQV6fusFD6D+FG3yocJ|4XPWMi%J7(_0KdGdXH*lRc zf|DfC`V-VHUsvu~oAOjJL+Gg?e;tthYPXmLZ{6ja~ep6J`~yjR`$6wWa?@H+tI6W?`UH3nE72S&~Npt zH^RDv)a7d{W2x%%{uqL_lCGW#g7&Zb^6!pUEs_vX9F7L<>DN5Qv=f(854Joy24;isHE}EYWrh(@nk7ax+fc2zR|fozu%V^7ts5!sIQ~`v^^w&|yp6dyXG~?2Uc7(y zsuf;1V@ALPQApvQjH>gc{bfN-7HU^xD;DI7sU}>3MEp+}E!CKoD1PMss#vQ(e2oLS z?h;W&a#H2Ny=!X9bSgudo&~ILY*v^;iyvzCim2cG#x{Cp>b9Dv9sM-Oyy%&z4avJ-uBp7MHDImuAO#j6bk3y}R_c2YlrOV?YFv2K9|2oPvAh>B8T)%A#!@#)V z=-kRl`*X+^o%|wCK>D%NB78JLEr&}x!VPIL{81%!f*4S}Zd>r{I~O)6zzh`|4%IG~ z6+YRpYT0!p-2@p;D~vO7biSRZ1~D91ZdR)oqu*$a`0ZKN`)0+Z+v*hK-Zpr)MCSR; zLmDRGh32=1EH@U%C-Qz)07Y>7}rY}a2k8bQ81 zrC_wyGO9%Q62^>+Ltm6f5cPMRdtyY{%gh8ZzcAu_EJx!uA5OyxREElA%n9-SFk5xx z_yk-y^pyU~)F`$%jlp#Rv9rfF70eI#DG%e>8i%M}_`8<<5bbdO-+*eIy-$85sOx(Y zg^P6)`rayqiO-#XVo5 zJgE(Idag}KSiz)LbPl4aT)+nz9|N+?0>RiGfa!kBD8ct$@F#Mq89Z*`xr@=3pYO;S zgfu^q!yMhdkOWHr-_KFLLta z&4JSl0aUytY;RfJW&!^h3^Lca!lW5n16)fmXbuF5yp*va1P*{$c$rzU@Ox|d&Xl)j zYZX^B0c`la#FOqVi-)s=9bOAK4%^Db!zh=~r}D3uuD+bC{*gKYapb|H_fAvX!G3;k z)6rWOsFnA2E#+yQor{5EX~jnQe{Jn7R?OegNv&)GiJco-UfW!z z3)R&09J(P;8?W8r_4cgyQ;Z82kmYVNGN>*98<#06CL&@VTlCAkAj3qKIXg{i%X!yb zkRF%+?pV1#)1O_Mu%u>A&?U>b8z#0mZ%Y3B<2sP6j0SH*by(o?OU;=mRocyWgmxF0 zHklL;?1`n08-Q;=*IfyS6oSOiEnRYwm7jT<>xQj5o2^!!nmCNvr! z^hvOD8tYg$>@Py!BXg1CVH1qpJ_P}upfz#1PZI9!1fMp;^BD5Q^N^gDZIf_Y7_!!y zR!q@DCH~lB7o#E|HDxOPV2d370}& zfw*G3u<10VrJ9J}mQO1IaE>KtI_%Xk{oS?)u`A0CB8o%c#uSvHw8Ro6FVl2Am)tQ5 zgZ*vhGr#`qpi$C}t#`Rtmao%ZQRN&A$pwLbWzg8fo32XKhaCTRj$~`@*R+QAmzkB5 zZV28Dq@8+jQXXd7&fc91p{}7V^vR**%Jxy5<=~t*kd$oc;e<5YE4v$gLbHsP+Md_n zw14ABK9(d!QrHmD-L!O_g}IV8(x*Nvk|)mh4y+^)iUU8uEX04yDJAQ3x+cvm|HqaC z>!qiN>1?vl`FFu8<|d=Q-e5wvA@n{a|8$Ki64r`OuT z9|ZI$IYs3rs5iHn=+y@|U-)WatI#{H3)%S4K_Lk16_~KqE@PLKnem%`fSpG~l0D|7 zQ4@5`Gm+(IZ-F51E5X3W_{*(EwTwZak z;xG0yy+KFWn}~v4p+Ng%0}+3P?D8W z0&*_S6s=Gm+WBD8Vh5CG3P6)?>iZe-xPv-7v2NwEa*IEaZBeZkn$?6;_TdHO00b_Y z;+vc<-iOOA4<+b`i-}JWfKCl24RW(VtBk{^aU_!lPtC%SN}MNf6v*N7<$c>%$8~8s zUVGIJz%+EYg)e{1zrtrE_{$Kw-)m5r;-*zn=_;xV&H{3f?~n#iQHU=*aXmM>fDJ6Y z6DRo&ae1hRXHnesf9p|M9auEN8~{*tCK+36%myUBR4TUIxWEB(SmSSO9oF9}&&^v@ zU0t?44NTt{Y4MpVD!646?#$6@VH|gk0yo|Ae@6r2{Zb?u@k@p^?;H!sg{Mj2^=r6z zh6`4wm9)s_|JMY+?xn7|?L=2~JO@FRmL;&7<}4u9luQJ)I92qS5Qx&zNV~snwQYqm z6PzTTvWAmn2>`uw~x6)_L^<>J_v(tL4ihh$;WG-Cs zl9}Sj8s4jG$URe+Ci73ojuxBhu-KNi0S^%Nk-q+)-f%+)Zz1Z8nbd+L34h8hLyq-G z8rY31DpRk71Mq_I$ijp9=5phtlFYVw60Q{05!9~G@Yea2UnAYa6iO(bpY0j%$*x{m z5nojj=&x)y8#wOIA6qVHbH$Qsoq5%*ZJ@wGH7ud)fNztqELqN`W1ZQHIPGzz)JQ&g zd-s+_n1x%?UO?BJyK9U_#Y2bJGXx28zC~C ze?B@`rP@FiPdr7oi$i*Fm$ykaVM(#>{lPH(7zvU-`Zx~{R|iy{i^G?XYG1(`9wI1P zPG)|@zM#kl*r{oo!i>GO^uQscI{NRx|JdOiGw4dE{I=y3un z(Sq5I9A82L)Uz0)C0=V41`ghLXI)oy(ts!JP={tCYdZ(1F8wwWp(|GEU9gZxaZNTs z_;`aP=jc)a>!(aVIC!@$DNAiOVDi6Is!anRekK?kmQZZVS+;t}7I+Ss#qGZ+W z;Qi^5nF9Fc3J5#E{C&r#Sz+e;Bb0!SOh~9(#u9#^Z#9_{sx`ehAdj%U6(_ENy$)DW zB1^+(ven6qW$xPY61|IA!@igzmVuPrx#onfl<2bcg(QXoAODmE$MC~uTREFFw=Vb= zso14=B>Ac@O-b`#>Q6!X3$rKIuf{2u@C{HQED~+Lz<{H2a~t(6E-8eDlB|GySc=N07hvmreJOx0UQ(Xp<**6Vje_M z$I#07+?`O}xljLYhz4{B7Lo&Z+u_;QLMjNTd+JKdGjMXRLxR;9`3Dt$!(<}}}FCr2t`9%mH% z?nb5qEQ|uZZy*r&#u%>!6Q6jn9$^+r6S){Gq1G zAucXg?`>yc4_wxfc7d-CnG zvZnbcI&`yWB8?kCtT-a~D8=GKhdt<0DV7Wpc5D;ai1&t=U^49;#<*gk+$os*PUglK z7)QNwxtabliQ!?h+!8wQCpo;XWHMHeYrx}l1>b?77zJ}_>bmbILC|9P@N_tn;JVAU zS;OjIU*UACh0g0n%KbPKjAI5$TpWWzZ@*yi#Sy|;`Ykyel!Psw($+<(U8XSmW=F^5 zO}^mzw93WcjWqr27uBTDg*-E6TtHGd{GPtB-;M<`PO25Iu~H2?*uI z=Tl|=lhgx#=wMw{cgmNngJeka48P0akmoKX*B4VMvFjZBsOX*HHQBO z9fNi$nwjRFUuVEQnf?NSwABFbBaIY{YH}0Vai~##;drF~TC0hv;4wYAp9?d9AzD_n zC8%oFC-ktKSmcdH^1-$Qx2QfUIX`Rx?K2TU46M*ya>h?j8gC)c|K~~Ef=+F9l`H*f zoLa3#9Scs!_|8wX9GVsJTq)^pr1 z8o(q8MQJHN#!6gn@^wVDr?7c|=xw4i7Rgj?e?ZeVU6(M zWpSChZH>fV>Efa=%yu1IEXvERWqdDj8T%otFDspwB-Fh$o^C>NNf@9gho<4}jGH32oAXkJlXo9;pfBFcE#;eK0i3Qy66xq-bV|^_#~cob?ZR- zch}r$#_~I~3UHuxi3|pSoC{?q%5{=UXxR2oS7At52>GFuey25)9-G5~cYv(xw`z1= z_xwC_cTEf8OcT+Wr*L)Zb`K?r4vaW(65+jtS_}V?ZO$6P=~stl{W2K{{RBewV*tn9 zx|Oxs1$tucr?2Xev~e)HJn?#x0_!jtPiygb2su3{0FYzsct7ZE?ofoa*%@k%DgRw> z^I{m?)??jEQM}jAIGUw780KrR$*g9ET}a}6Q{k$qb9AWXc|UiW4OPPOE+dp{B4f$7 zVL{LTIPizD3T)RjE-=*9RGlcx(Cq|qINr6w<4d{Xvj$&>s)5Bu5)xITt6rAuSwgVq z+=8?c)JS1!IyhJ$VKjh+RR^6(gYT^BHYN}8Mg=Q*tj1vf`J1))PorRkiN|qQ{zf%< zKUjsNN{9HbRioPqb~)9H1*a!;wSKaAJm{{;8ez$@Pco@02?M-Pzr3LT33a&1GsC0U zW_%8>JO&Db(%yI6TY@Wr39oHqOtXguuqhxHea?uY`Eist+#?FX>^|fB)t6yVjE*+y zRTC&RI)suKT`SKhWG{@DuPP!QEp zkwo{CmoPPOhj5`8o!p&$rEjK0_b`LH6Tv+N@ya1FUU8aAdyp92B&rfRg*$z@t~S9$ zzbr3Uvr-f1$%Z?a3S_E2WRC_j=4yfo<5urGThgXtZHEd(8ovLr!UHLiH}QXN;=9DRtQxm|Q3~vpdwqo44vC z4sF zafSp*sq7kYD70x!|0e7MqU`jlB8*?C~yG*=zI7N;<{QIP;v2=nyV9zgS z?~fhU;w<3)Fh!k8ky_ZMwF_WBaknoouc<@c*YXHiRg1vz#bR7yg~!JMnH~(7hYC+i z1_fR3t6OGDu{DBTk)|2HUo&CRGd&guRq-AC{25=7HLH?Za4cGE5KEn~pbZgQ)NMWE zufLooJA-(_qcNZ4{pH{r97S#ds>I;fEArY@{>%c%$JhE5!pqhY zECBBeh)UdpBM;0vu9rxeaD|^yz$shLH!NE!*RxY>&3?;R6+M-=o;O{Y7+_=he3Y%xDv zdJsv!AzNh0K?JkHdNdTOrqy-cdMH^*?zRWFWpFg(SY;)$?1%unqPmyzg=W zO1enp(>pZOxN>%yK|St1cqwBbn_;`p=01HjUYLFQMqCeI83c83`G7V)h1^Jvft!U`U3Xw($3 ztse5|NoPo)ITRgPTrq zEwQIRpNbXi`ZcYdZexQlFF-#P$SuR!&}Oc|e&TA2_QEQgW_^|(=|%yxA^mznJ$x_- z@YfcvXjk)doQslP{TS4t;nnLdy*T1#CblSbIrh>o%485>m2P{G3-P>?9U?t;_r!x& zqY34`;4wuI%Y$p8-59jEj7xg{CEFyi9yRq>WnzyvXuv`LIFY!QJY3AbFS#W~M#7Dm z;O-n33gFFdlS&q4aWi4dh&QQ)L`UJCxtP*lKSY+h-+2f;3Rhtu(1tG5M@^6kbJ`Y=7v2!xRfXnLfoK4qfIR4pu32 zlPxfgdYZs=cUX?f!~l2P@1z8TMMeoG;s%`zPk)*(hMkr|wBc`srxs2&$l5y4+G4*B z#m>THbcCy&qGm}rLC5c>k|=OeHdi*H$|+Yen~0iSG>3qmQ{&mmCXzrX{Q^NJ zp(0#eSrh!tkm}vw3c6|hh}^?RxGu&WY{5LVvD3~ykT6?aBc!_%urRG=MH9X1Gn-Q4 z7OP}8@O8MXnX51I8ClwatDOb*k=ByDnHy}5ZWlxBhcf%f8$~MK%Jf+yZRk@ttMW+_ zYn=F)MYi3XuCI08+P>9k;%_>sv$NOAp+}JW{5ACm-nMMq@(5<~Ty!hXXzlY|u{MM% zD+zTD#w;0wpFPX@)A=-z6~@8z#b@sTzq3k+9D94$k_{=(x@q37jae16k)R^Ob^m^! zpi{ykEGr*+_JHoF+1a){=|qd8eK6@2UiY~m4^yz_XU{F=M|$6qwqE0V}? z^DY;W!Yu@g=vG|Y=PxQrU)-KTr4$L5=V#&W2_e>s{f7Z8*(oSYALJ>7VKXYh7R9}# zC*2do%!NmHmnipx9G2@4Pi?Y>9+1-kp0fL#C(IDXSL_4z+QRJLW9<>0T__OM*do`m zvDi&zvae4p>`e~!?0NMb^5L1)>r1>euV3BQDO%!K&Fa2`B6i32;jGiUxXB_fK;(l7OuR*-P_j zZ0WQRbSrEU`<;=q^oWl=*cvh?($|CigvBvm-oQVW=yyTS+l4mKK|KuBgLJjB6Ns`iCotS~ zNcLfLxLydk`tcxBiKG(r48Tj#LHJl1A|`g3lhK*fmq&aAA0ktE$B>qNk1g^?oBN9< zNmi8F!9FUA1N7Ya^E;9Z8w6!d-{B8KF$Cy%WI~CzB;wm~x*qcx7erW?<$#!^g#oX> z4MlZYtfjwwI9OQk4i?qQkh2-o01@6>OX2$DF=3ydO9miENv)Rx^}qprf?Jah*co%*XSZM zM}=ePi`MlI3=ebQMliok@=B9gx^be{*R#@gU@s$DbP<~ZcvullL6FaOBKESLW8Hoc zrW3Ns#MSnOKXUget7RcpMX(Z{X`j2Ow=L9C%1-DP_)FO=_IpBF0-)e(!kEy-og}s} z(hD`NwxKq|;mivF|33i0pSOp5O3@&(P+A7fa4ucHaYP=72ka1~#M&!a`)*O7(MDL~0qYgz{i zzScdrF|0M<6|4(h+mpLJ z{_2lc#)uS6P%b11wOv0oAtw>hSvGFF5P`L{VK>?vk#x!tmA-+lJbH4Zfw~=V-bks8 zIa4B@E-yn~>6h^4Foo1`(+-=UY(31oYs9Bm4tjb#|8STUwDwhgVe@WIcb%FY4Z6}{ z&7YuLh44)Pe;DbkEQ#aAWkpiYDtyE8Dk1>_jB03p(>Vgs<^*q-aa7a3;H8kdX!kto z#Sxy>xCBJW3Dvx&ij=LB`=4PLDJKfO4y=7z4C1zDJ^K`T9!tIieM%(|jRH0C9i-TZ zp_F!=uRo{o)o}*`5j)6Px=b?Xu*!zGUt7GY%+NQ>!osDNYVdW_9vSlB`e-Aqc$gl7y!cEc6@GVhGNP@<+yF%34?pbG|I11sHT|n2Jm;HuQ5#U6~ z>P9Gd4fy*%1Uro_5WuDFsV2OG<6E#ApaFZ1DKI^j{ydp57 zfqVgYQy~z{Dpn~djh}+d7ZOa~|sOC+{n?a1Xz z^1+GZfvefIk)|B^<07&`sC#?0I?qD9<$jZ}PreZ~Fo1+pbW+nY<; z?5#Ci1PZobPi)GA2%D2MH9SqK1=_j0p?VQ#u10yvUahe-`@Aa$Dp3`cw4Y9Kb@Sqg;pe`W7Sx&wtrO2?R{1%zz4fQ4k3kT zQ-8u#pDQhJ#=^Jn+wzLFNIRRMzl#60_r6^k$37T>gE8YAPU@c&2z}LTf+QBwr~(DN zP|5K18Qr=E+VKXVK*BIt-fTwlSGKv3z5=0ejH1_MUp;W5e;~;m z7vUcI(99>;!?7rE(75B^nrtb_S(`5~)ft^8u<@n$)brdZ1P^|FfS7`LyhGxL%6z@g32-Hh-#!Sj!dFQ#Z;co- z`aa7#S`W`uNNCR1Hw!q@4%}a|H%o#c!y!`xgK{xYO7bD=3c?S?a_?!|TndKbPD5GT z&$rPu63eYtbH;dkHnU1F@0(5!^fHChmIcc-AX#QG$(%j)L^`J~!sA{_u}80YhP&8P zk^L0tFY$;+n6Kb7|7KafK?iCO6VT1*vBD#IX*wHTk5rw@gzQ{k5NT7999n z0joh?q9GQbexMK7+!Sjo_du>GzeMvMxpU~8h~NrFdwjaj70(Zo^6MpG&)x3;MYAim z=*kImft!OwD5@4HcVBhnvaz=yaq~ZO=uIK z%ctz$h7`+bpx*sKGPO%3B`W!rh^gH(-*&wHq^Y17tqAJ|QWrNUz7CxevSr*n=9z4i zX~)E{{7=xZ0A0oowy-jV>Ul^UBcwoeRX(`hX&A$MQ@$qU5_lsna`ak!IatqE(4KAN zi8nrcyAarE*ZoI~pcy%hpv$hx6y{^BWrvE?J0L1*F}ojAJ^Y*EyScprK%0i5-nix* zQP!m}<4wRoM)IDuR84qpiQ8P-IDJe#t8l!BkX0OvzP6OZ zWmhu_t;0EHmMfwEY`>wr*{ljOdNB|0?^LDnz&4B9G&iu1v?`PEmml;Pz6I2wf*7eL zIH1xiurGaWa*##z6i?_qpj@AX1aF>8XTX_<8G2@mC;^?3l-Bc;o1B=i3|CsaEx3m; z0=VqMApS;B;WCM6gu@qMmTk7?v?N^{$n!m>l)k9u`+2EccixJlZ;`sf<1c@i2&OBz{_jDSqOtaavDeJSKJacQ}J7znaYtkJ0Lqyotsy~GSNt%)pj~xLs-@&C|4>d9D_Gc8WpN z|2}Tq$0vzbaO)tJIj)E2dWl?65|fkO0@8S}l*~BUmXcrNb?vx8BKBy#+e-jx9^LbAZm{cM&AYI{q+2kk$7w#=^xXANsoD6Wd(nEQJNt+5=gs?d z{+UDa*98(g4+_TbB>WoBG#?pPHbo#{OjqTo#Bzc#@*{SqYawJOn|P~BBx#Kh#v$}t z!QF!|7HwSsf4yHyP1mKBntQK=mS zcjuMF+2llf@l3&HT&1)9<@7XD>ECV%e>z*-`tAh<1FM<>sQNF?u6?mwKlDfLh;Fz_ zTMS5&nchPQWwzh8LRu2Wy-G^uv%`&QB9}@O7-V}U)}*j}%Pe+f2N!(6VLxj=_5o!Vjz9jP55SJ=K{?r*Q2I zQV*Qt?B2IqCP~3K96~hbL1!!)DUI=ktON*~$^)`w4M9UL{B?9gd%UFYelJV_Tg;df z>V~BJ!9%(DXJi%NP-pU|6}izK`&&Qd!s}#wiU)AY>654E13*xb%iy)9a$k8W+Z~$* zK~L48i-2Q$PfbB9221|ED^2(3Fw==W#Q=Al4VUsfCV@+kQ@lAKpDX?7M^JjD~i=tQ_gmVgF6JIqsAv%3p z6AtLt63iJEcMWvt_;a+*yBYQn<3NZ#1gUSzG`X27`m-Q)7)bs7cPR(b7HQD8V43rh z3DOD*e8z|cmNKV9R+RBC(gmW~c3j3(ea@i_xr(7D!$z%{uj&G#FN9%6kM;dLcswm2 zBJkKMe0!@NXpS6|;nQL~;RB{x^4|NHRqF4~N=`2`7BJo{9a6DFoLhsQj3gAcGr1N{ zUIF7s)~Ts^BdVJp2Rx`2XjH~2pA{>}^i^2W-B|kH(c{YU`8g-gT^XITvK~qFmO>*^ zUq(?hTx`kFN#Z-^!WPcj#o%sFG(u(Vry_ToyMvE5a;LyQc7$atPc57fJ(M{W7&FD+ z&LmTqpL$mLTk)-91x=taEl_VZ6DtYKYl>%jM#nJ5hALce&NC)Pl+q~Et z<=gC?>UKYw-0c<&UbO35hPjrlhWRjwnoaR#Pb(#hmPxPxUzwTX5Sj;h9gUcEH-S5f zlk1N-a_}glbms5qja$xjsc*v^gooBVwL$o%VK2sR7o3Yq%}~T& zSFqCaGmPG&>H2a{e>YV_knLyNkoA|wae^3dtW%VjJZ&KC#G7K3KLv??Pd9hkOLmR2 zW{YKb*ehD^aka+-@HHuvMp)gOLRlkkK7&ptCd7wn?{>B^07{|5HH2pFz}gmx$8;u5 zh!X-f2Ykq3)qA(*)=0B~as#RsMrE%;wR_AVZBQ}0D<}%eVgXuSG&3Xd?pIsZqJ;`*5&Pp6G6UV#4H_z2FozrBc?JmGTsgn+ z#BuRiVC3Rl@?MQGcuyr^^0LlS_O-Ul%mQWZRau&9c!YT9uRmcDA4(p1ZWgR5IMBvL z>O&m26?vFt`ITvRmTrH5c3JgOGR>|tC?vh}scxmBaf`i6^;Q$JW^10wGIzB<@V;X3 z@CeJJeDE5(}-FRNIIs+;gln0CpU1a>eufC=Gve;kN92l_!|>-yw#60&$lOryM$~Z2uCm0z}%^RiV;MXEC3`|M@K<;qz3pc_irW`J@JC-8qXcfs76m_;hu<`j*5aL`wu zQ;<6#%?l4MsbZPR1X6>IXw`GgE&%iUPEO$jE>(BquMY!)VF#_TY>7tRtmY9bpcJz> zo`)01@dgjC<*#VRr?04uM7droLFKWVh)7kIUaS)6<;&)7RnhmqG_o>36u19Y{S9L$fekRthvxTl*4oE9 zx+S4@opc|>K#~YMra629!$*AUh$^n))ezfD9pj5SV@Gc4NGH4JmN|LECm7TbLPO&_ z>JYhyc&F|#Lo85_#wj^wi10D`?@Q3gk@OL)rmSxg{9CPm7h9~B72DqUDxAOvS~prd zxp_M&bEi&^-Xg*!7G-bg4c6LNjO@PxaFlX*U(bNcRIJa9VMl{wd8_fR?K51MELzQp z=4t@jxa1wc`zx9>x zHi<}ikPoV_Db@Z9q*Jw0YL1O;p=f58F2y8S{=ID(Gsvj(YdtSOg6Ie_&UZn)I3${f5Su-M|NHw3t){Y0aw7oRx%*`Y?qQKQpJ+|`@d!|&njqF;E?Hbk=A-rP zhqrpJYzDVvZrfSYTN1JMG@YJ4!<~(=stZ*h3w*=Q@?0ryh;iFq3{0X?@C~PX5~-TI zB4KqF{ptEeb$f7FmvY!%I%lrW(Zq9Hl{es>-9taey~JkClJ|~xsu~WWYaqzeVeM80 z-U|F}vy*TBf(^eT&y4dnWHG3QPp7ZMDO~I7VU~jn93cr3eY)oX(`atPnEe_K%y)V7 zSr9%L0t5d*8u2#qCWaBxv82`(clnG2wi~yhfe+rj)wAg`^|@2Hm3$y9j%VjdAXc4V zhTBo?2{)|dGIZY2Y-*PJ9V1Wz^g5sm_>};0ZIS_}ztU1gDpRN=cH!}Ya9G(b>0hbI z^V($|?eO-sQ9EG*v72#XBXWPwLWvYj0d9tiSb=`PbyT+UpbWpJ1Er{W{HYRi)P8Jh z$0gCev!(`J-H;}OxZrMRXNy74p4=ZqA45h(2hnT4C$3j!U{UxJX)&F%rNh7(#Oewc zt~+pXf=XHuP<91gKg#So_kO56a>QL@>K{&z$Kqh|ubTBaN>at#P~6IM<|A0>=S4hl z>{j{+A5DZCCXKEQ)3ihQU53izcOCm+omW=6=)<&Ia|D`zFbVdl4Ss%jVgUmC!@kOt zm|~%LxB-%y&k1qC^>2=D>>1SeUpG8-2XQX~Z10 zLPpt@bD1_4)z^8TD&tq?`R&PG6IU zS~8^wt}pz3ST_@O7gO#gJg9@utMNoj-7~n~?8S^jHg*;$J`81i{cgT5tijoNiZQ5~ z4R(1=C-xE_;p#RwnFW9!aw9}%coWuEG1Qfg!p|YptgWt8m~+DGLK?>MHKK>CQm%Bf zLS=n;r^@Ff4%n#luXQ1F5198y;*kG7km}mv1EXma|9C5qwhwb4j2hxDF$9{9rM1c$PhGFs&_rn~9{i}o*Ja<^>{YQk1 z!1`x{-#`SzR6SmgocfAd7^QWPZnb~N3+7Q1D)zUYnmnGEO(w*$-}e-FRRi&xvw8r; z?Qn48WQ1IIh6k=jB{ztL5Ez6-Lzc^6lF~mmx}W@`e;4j2Lo(_?usnbgC6>7Bm2{%s z;17P20ZVY=9W&8mDn=bHe$r<~B=@+h;A)3v)B0&x#800I24VGFM5_O@It(yc@-1GL zxK%O{Y|Adav{(Aqe^vpas;5gSG=kgzHG%99yJs(HU}~8-@hEEwNS$T z`*VEuMve7n@U}l)7?_Ej;QV2ibFc;oCJuCApvO)+z0DZL=~TnbdrKALCJTe~V zQC-HvPoUFC2!^FZ>$~rui!jb1A$|~TM=;i++I&x5q(nG9%>Z;`F3(?YqiOq~)9q(M zruO%LD)xVu>waYmjzYV{A^zqcCQVcv#~4R0KM^|ue*iXyT`|6wpUZF$5a$VBmy7uH z{O97Oq)b8IJ3`(c`btl5PyAQ+RL$kzmG?L2qBonkB&!}?pTI-`S9bC8d*i}bk3C(8i0#Vh# z1KoG3&vUyB(5tcDLrE$icuGHld}m5XsuoSlic((hk&PB6@n`(l`;f9hSY;TI^bS2LtGzG$Vh(lriFX?CBP$Y>m z-l9ZPz}~GT04OjS2wKds$$j@7`tfa6Z?n=I^#R3Y=Vlb+#KSti{N8_9MiYjw(PcPV zTwXhYXUtG?ZhaIEFAHfXC0A606LC^y4j>}<6ZLb$tUwuxY(vrNkyFIZ$iPrfZ`+> z0UGD>1Q^**6D3?ottx#_Tb5lY;k?F{K?ZXkd;}ce2{y7qEGMh{HvCb)?XF*Hta_*B zm#+kSm7{&pT0k;55nKZE(c=;UpFR5mW%*c!LJ=kh^7)J&*i9>$v!ZpYwsURD9{_H| ze7lztC$jI}t#bI-Ro}=gQO_06j6^78H-;8J>0iH*Yn#eY$M>5N#iV*mT})%Z1cY@Z zqw>-U#wKrj&iWh1XbTEA+ZrsVW||xntR+F&;Ut8)A%**!sGzKAw4WBwkd)~vmq$@r z_0|MPP3Cxrk~LZH4^zeG+Y?+d`n(;!Q(KJS`^FE(WGJ^zT4%Ey^3rhta9b}P$2VIz zQj#icf@r3sUtC;*Ct3AbRZ~c)q>Td=)cs+z1eM$4wyvTGibEz>pxQmR+h?4nvrE4l z!k)?wkl2=wn&9*NF*X(Up5)QbaPXisAP9xwBM*nNFSvC%!q z_}NwAsR&slL6OSLqx5Ug4XrpIn}x1!6%v51uGF7PClJR{tf&H*h>tlL0q0?E((XTh z>pF)QAzqz4xoGmtTtsf@4ljdHWC{d@HzX~{V-2}XH@WjtDGyTt(3fFBDC+4H5N^2- z3s9-i=81!EjeELXobg+YJpv=^<58~mgxwDo)2Tw>_#B#n@LiH z)MSqI#**Cp6|$(?o93ij5;Y~3v=My>d~HS4QhV8rxra>0Ks{q(oogV#a}L$`FZ@ENfF7Yq`*mP;XaN7u`cTI0^*V>B={W=Ch#&1oxZ zy@%gU#*<(x6}kFe2^!;OA49EeQ6^e&6x@@Ij7FVP`%;K}FcsW@^or#5h73B07mhHU z%VxK8Zr9RW>x0{e(td@uaLACoHYMOB79!&TeF+p>$FzI*ZK8=!1v~(qiyve?`}w^0 z$7~@&5fjbN{IxHf5AXBDloiYw4cx!<-neA!I$Y4q6Z%pO>J``d9sKN%VmuzMY_odQI*|tO6wtD0_f zNlBqKH@0{b&sxYyv7K=9q3? z*9IhA^|gd)l(O}}e#ZC??QGw^Cpnf{@FhYzO8p$7DZbi>=89BIHc<2s=I0tY8PtP9 zXqvk=?-8~S1*mfV?Bvxim?DnXb8Pe`SSjO+w@rns6XPbr|4C|j$$CVPQ=zz{v-FE( z4Mik1_Oxe!+85Gg?5$&ZDmt+TGu#^|b+I55_V}?)rG9ePm#~1{OD`=|=mv$&qh#|h zXIyt2)%w>gjDDX*^`Z>P9R-Pq@^FY~L=@Z+UyeQ4yb(r!)#9Xxg`=T`06d(&@y4&f zX>XOd_K;Ic6!&%IkqTr2U4%R?f18uf=G;#2D4|I3^i=uO9G z*-@#^Wp-+sH8b~Efr94qaF%iQ{6H(nczJrl|Hf1w&vZ*U;_j{&$0%oB3G<2-kO-tR zRFFA1e>6eCj2T$5%9${RBqGdRXt8uunBMvJt1Ilj1pcY%h@4DnNokW5Whcorgt%cblQlQsX2N2N-f`zZ zqsjW;G8ax6C`H&=@o}hahur9XB|v+w#FwULXeTo#<8?9&b7;W>Tim|hhY&%R3A?ml zAvbu#D3T~wq>}!IxZRd6PnfXb>Vl7os|#lfk;RtDx*%PX;9ZurNcT34{+?V~jO;7p z*-mP)j^B%G@`PG#M)w^q5(~D^Y}Lu4tv5=s{qMd$bF--do)yE0G`Mu(0(yUSMaf}Z zp3S~Zb8M7cm6rTvLcW$);8m4+h2F1`LpSme)wC0t0QE0x@!V#K`-JQeU#Pp!gD@Zi zxi}S%nJR~Qik}qJaWjwJ9iSpZg~^yrY9)8-(+VN4615X3gA!bqusFgY*M4jFFu?RZ z6rzV|HqnNF!NSdXw7KuT6tq+Pz0lzfDk1U>*tqisu6^?mM4mG3r~Ln&FK&z>NWN?h zC#t8EZ?MTsI2y;XQOV4n!5EG2ktIF}r7cx8UBX(EP>VEq6u5PA0`0=Fpxlr0!@1H` zs-w%me*3*pv#~KitB1;Zz|l8&%h7Hq(FBFIlc9!kyz2q?{e)vtW3ho!q)Wco+5P{v zl@LBo3&ORToa@=eW-Ni3V@%;g4E5~Pgy_GKu0NcM+|3T9<5oj;R7QG@5#aC=2XdbM zhXQNCV^ggviGE}N_Eu9x>K;!(DY{qJJ#RO^M9Kwr0S9lKkcgOM3ni3J_7n+@&Qt}U z`i=#p8g2vz+uh_z0g5yAXW03FKPmo1eH5T8uuocYck=EKokOqKp3^81*YL1;MuJee zYlAJfX}KFhA)Cx28Px}|iffgzI8Uvz(tC(&gJ!G8sBIrKh}V+cAG=Otz6t3~nL_sL z+2f=U9%YFE?1YN5-z?NbBegwZ;6Y43o#{u+Ym=Li?>d`^=&Ljqnk5GoTW-UKe=!HD zsFlX{N84Z4q1Qs$H2mtrp| zNJ7GhDKh}<){~aC!w%q57rrYReH2G|ag_x2I4kzsUMikc%5RJ9S_w<%D;itsndPfd zZ;SQ~kBu{uq>ivvG=x9usnUx~sIPTosbL{p>FxDnNI6ORoLkp8s|nnp2x8@0QuU2Mkr?;UKJ^$_*RD?WJl z$#a6k^d9=t4(L?<;ocD#Ih3U~9YPCygwo1>AHjRFDyZy)wq zfJg7UX}Ic({sTJ24&=$?zhQ)Sa8~Z}$eTsAn-D&@jj<1u_!XrJUThjiAig4kl?d9D zVB^59LsM9(SEYYIHMWxEY2#D~hoq0ew`ES;10pc<*wr|}eT+t98cIvPY@ z3Q`GG_6(?C5*J>)l@>z#ee^tE%yZ`W1Wof)c*zp602ZxcZdz*NF5iZi0j*0}&(2@{ zGPz%Ox-Z)XKuMJ?3vsmyI3x<6XRACgr-gq35M0j-#i^w!cL#g8!DUkH_J7fk2WrUi zkblIqNv=b@jpZCi@vxrWq|g-rB8lj{?D=#T6yq+ywY=t=QJ`a4Ws*^bn|`a#>lA!* zH3i|7Ssv~y_&+iQ6xNSxB2K>ejk0@k+c&b~ULJn90c#ORM!xUv2CDW@B>yF+pL0^Ky$ZtEWeu@y-`AjzvV z1KreVQOz-(2UPt}auGSfhR@0Xe4hM9m7jNNA^@af?A?WhS50mNPnGc)UdEx5{Q-zW zB(BIsdt4!U3Z;eL^TE~C!cL@si8(n7d<>s|UXkh;S5DfVs;JeWE{gYkiYt0xA(cKJ zL9iA}@@cD&JKLU7%pPJC7VkiKszPM$rlG{Bv@J?P4E$~`TA!v5yO|I|h-eE3(&AUO zAL{Q*-ZK=b!3&+b6su)RQz7Z`v}@^MXu>PSFkOdGQa*y@{m_@1i4bcw^)X!YPmtQ> zcG5>2G!&D!TX|jVT;2?!43P_3@+hcruRXk6l2D%34VXedJ)rCOcY6m~4w7yr9sI){w^Qm&R0S8lIHw zBr&Bq_XrJ0@LQ$YFUO5ij3x~Njf*V$-G0{=*I{h7R@MOKQ>in}FLpX5q063S3n@_i zpB>zVa{~UhlW_#byiD{t7pr092P66P_~@U26G z31uZ+RXtuX}5V+6UUNsstCB9KfjlsqMtWX z3UbpjGFno)A&rlTz-vH4RtwoNuB6Xoj74~*b&0*062g}+$&i@AUse@ZlHL?IA_~w(uN`0R#cdg$v zu;%k=rBeZR49?PqA~z(i-4hp>Qt&EGNKGCi$$!j^UC1I|ow3&}oR1t&Xz+sKaQN<# z>VfSRuolCLP7c!LQXIN5yI4{sZ{B6S+}aD&AS;((VZ?}G?__CFVnEEgw|L}OW@}>1 z!5^g5r)ljkLab-grF|$glduoq;y%O)MGIWbSKt%dNC-5n^&MIhTg%#TBHI!470px- zR`!qh=8pSlS)dPPpI!U+?j*&V$%OZ&il?9dmQ&ejy{{SF9vbT++=IdSE%32aA7{u8b1T=1-)KuC|N8k2p{RT^P0?@L1aJby2f z!49@{D#MA+E~EH@@~YR)m0BYFt?d}*Zz2=$b-Ip~vG;AHl4p`B7dqLtcqjri$7U-foA5 zRdEu#S>Nv7@-BL&E|riFowwIJo%z=ToWRnAT4>TL;?nC;x`p5GfDu7^q=SA8gacY< zze#10WwcurSLD0cf3s7#>y(Of#MZKB7%z(ZyP)xyvT^!?uf$}&6YQ6<_v(iEpbF;U6?KeQ2%&@S96x&*I`84nJDOr4 z4k@CeRUq47aKgPLe2Jd_yhmS5NA5iF;P87p8y{9`rCZpoBqgAK#L;$PEw@s7@V+aS zP__Z+QAkj_@%wiIv@Ju-j(sa6XZg7W!6eOifc~~HgZeN2#sYIv&5Sl!MrHEU^9Ls~ zTSjlnKwJ@ijg3aT;nn)fNMhdwvv^B=m@ezlw=r?WVoHTn3^WS#9x@I{WW3l;3R*pR9mtA3cd-RZ(` zu1PEU zyL;>d(3TlJ^Ax@hKl+w#DIg<;akrJ~XIwHYbZkuDiF+)gu1N&(4aN;Vaf)DX+*4KH z54&im*khG^vO~!d3-_n`E5d4U21uex{~7++%Ct2LJ36eEg9b zrTwJfvBeK*zhy~)MOK1gBl8qgzmsSiUd$JkH!)DX5!*5PsD2F597K(k0xq!U%aIXD zZf^SfwLqwUN|}?^AbtK)FRk69r&gAra{gx~U_wxkkmmdQdR=SHI}0dsp3{Z;wdpA4 zE-`bvN*km5u}YFewWu&0G`~H3$Ryq6kJYvBs2wo8Rt^+RXi@^qZ*RY^w z9QDBBo-te9V~vCGkM7ixvo1Ly+iQ??LX`fTUUbD#EE&oAaRO@0q|juPEvm_a?zNpG z&M3c_4je#_C2`aXN8H6+835g-*EG@4X`3=IPzM_q`^y@TYY??j!6bdCHl~xfaKxy$}iblvl~nZ{)4h< zF5ZovBm{6TNOZhC}1d=VLC5BqXK{J&T2%<}89sd^7Eu(~B6@0~- zTSoMFJ`o!^(AQsKLa>YtYUDtU1VC@c^9h*U8zUD?VJcKZ%t$0sfH?8YNH~54#;aAJ z47qyW1eWG_JpZzhM7(H4E~xPu*3p&L@nFbf3}SH=VZe)BLQCUwCtJ`paiXfxC;7Wq&xz< zMk9u!VMZKFR>oR2s3h$8+lMEHR`>(_TzFoELTzTGhUj!!J^Db9oYeqd@c8(Hta zSJ8Q02^Ny_O7+o9+`8bq=hcvLhFqe4tnllb7EAwHc^O((#T%?FgB}my5wp4`fyMF8 ziy_n~@54!K^CIQFrOnKVX-E3O(<{E_E!PXuo@6g}d=WsA)5a}IxRtPCkW_4FbP@F! zQUAW7Za=j${P^NeT`l`UUSS-X^^q4qGihGP}EE=3tBoXpWK%{}!tjvS$hXEyg z`_RhM+^_k^JP(Q*77R26Mg(l3DIsc7#RAWT9~w_SETjatS+a{-nZWjzjHp>g>lw71 zY1njtY+-uYEJ}0U&Y&A>CG0qq7tj}qZqUNi*mU7yF?FGwcE3T9%<8dEPF4L14 zH=1R2rTHZWzXW2&tUq@Ct291A^p9)$7Ai=u$i4AesW`!EEzS{InY#4uMQZkNIRb zuZ+!0I9$orG#BZAiB)S39)BH|!)(U;v^VHpY)HO^i}{$oB!5{NshT~$r~V)k0r#P@ z_1SQ60G$^4U0D#hfQ71S8d7|hXOc^0A|y8@b-b5MQhw(P48GiIMN=26yO9e_Ze64G z^Mrl9UQlW)5c6blIDGoXV8S0Aw3I#}mS@b^Z~dUU2da~Lzowy=_`oYWmPwdj0cET( z5dfobf{tOH{9g3}o3`2~un~konc$G%*HNRtAf=B#y6_h`RJ$f|I>Qp&chpb$^ltD0 z!-=(#B1+hyy*r~_*rziP+xMLyasbC@)~BNgu(7N8h(>VWlg`Yex)07ozxY#PB!`O~ z^9qAqhrUbmH^5bQTD$rr<9)V}eO^TcsWMc|^yJGANyBky8@@nH2$yZi-k(~fTeQG4 z9c7M~YC8jtDsVwVbIuleL5CJFgZ`An`q2<79H%T)QXJ~CB-T#8S)F2{)-Ku4AX!T` z<{yDQ>MhC|xpwrqwn@hka!zqf8nL~kuBwVQsY6DfuxHb$mng5}-INSjl&QXQ0r~x}?%BQ8851j&jf^{Qy>8_25U&YI;V}JTBYdfP_q) z;tc?yTIv(1b9nvZ52hD*_(KyWCS=ZY-o$Ao^wM6s8 zHWaQf0f{{(r-zybcRN*BRZul3HR8B#iox_M^C!FKitQ0*a@h%%3hjtJ8ID1H_urlL z+gsV;`9s*_n8)@>Lveb1-qx;_Q-xW4>?EPrdJ|e^`aIC9uZmfS^4gqCi7}PUi|Ga0 zulnmBF50`r#_g=O#cWEDSlD%r@#7If=Sd}!T%;9ptB;X~xZzsvAya|^(z~@}%;bct zmEeh@J`oq&rm7!^>iM5{8agm~NY>e3cIV1R;;`p`t~?k|9KMn_fS56zEABOy>2+|5 z2Z;X>q*O0PkX<9gV*#uA2oH2& znP$;l{=|926u<=v1PfTUBpq^qqGQ*ah5QsTp`&9e1L3|p=`smL*ZGSU&iOMJOfoq& z64{<~TiWvqMu##pVc7j?M-b7@Rw-F;M=>zT*EKVfD*ExTNBhBe5#%{-I^M7y%(fl1 z??3+=!43}8olCZ)A}H=syC2m6K`%`#bNHN#u4wznJ|AIC(x5ELxZ>5Z0pTp%_4~j? z0Bt#hz-$AZNng#ULZvNe#Fn?SceTH9->Ha9s!U3l{`E?ScN6S{SOq!FPs%f?l9(7Bfnt;9R=#m<> zK)tEK$wWS}0;ao-)@N%a6bX<2OwKs409g~8i z`R`o4b?XJmG!sLTg})*4y?vJ-7$UpO8Dg>(I!he6<21%;>gZU;9eV+>wyf2K^UXwu zGgCdcKVY_c6PlCh^ttLRoqoM*j8hBCj8bmX3E*@9qa)6>QgS`RgZ; zT#DJmOxjzZ2E52=MVBoVPCka>yjwM!UVdk+%=|j;K&jUQ+i8HbgNRfDygGrM5>v8i z!%9tofq5yIPsc`W4>l54i`e?yhqV4$5_vY6FMI}_WvV$tq!}N8)I{DD3o6=u&A6tj zZgdx%nGW60xG`!&mAw2d6!%FAAA_scHR3s?I3svoU@|>sELE>zFSz#MGi#G{oIdQr zjc4-w0=&0B%ws6`=AwJ59%TK_H!mb$reidAV!TUz7AIG*=|-lZlUSYg?8l}^(}#={N=~s*91jvcYRK@s98z@m!^~=!U^V;Yi`BVPY^DE zvpkB+?BJYKwh*?gYnLiKWsMsE|33i0-KU+5pEEG49x6VMMGw|?dktTy{)3FGn2&{! z?K->_AU&Xx4)aG@RH0|zqCi9Uxo>rrLx)Pugtai%qvGT=-~!nY`F(&A|@vV>&2` zdaDGnpf1k>;_QK)Pt5dm0&aLPzgdUB9GRRvnKvB2XiL8+*9h3K?u)_q;P0u#Gej)-D7f@p|^&lP-cXch&3|96?S7kcibF7$+IdY&? zx?E>Wy*N-5XH)7D|Imy?L(g;elb+SYfbNI--pwslL+mpQE?S{?08|p=W0RvKIaPlj zJaOadOCzjQWr)xUZ!ULVm78%IY;$mpuLwGrN7UT)^ zXCa+NTV!kN2DV-fU9leD;w?Rd5B@3FxQHZ$YUi6U^d@Wz>uzj2_zJ)ZWhS$CB@7Lx z{hrG4VPkeOl(vZr(CL?U(nROzI9a8tN0#4Qh{-#N3;ZX7anYqkRD6XS7Lb`FEW5fRAYZRx0k(nLeLURck~v?v$)Dkf8OJ5{FBR6@whgo@J5zGG zLXWccMPaXHZOtKstgoc&HxqmGo>&X1u^i3;DyrCxH@9!ziVOr9jN>EFx#-qGf?M6j z(tPRN{F<@yAQKYz5_j}F0|-ad;8L1%O-bBIw)nDsV4H`8IEUbAb|7O5`Eb;>AUB$X zU^nSDr;y{%1^#m=0F+eIK+Cm~!k5=es@w~fz!OdRzrcmS^>q!Qi-!$QVmJ`=?jA^} zndOOFy&-^D$GXjA?n>1TlZ3tWKR+2+gJS$h26mde2}_hh;NzqFP&YgFNf?`cGROP1 zN3l#15oBBIFQ72?;q>w}E=1GWeM9@RAsfoOyTE&uv~lzqAzdlsj9i?od%#tdJK+^C}ti=*M{&3z-Q z-rEA*WG5;%rBFoq?sJtbZNz07CI!nJ#>iI%FUxHqiK+`<#B_@Pev>SpO&fEUS@g`d zSO#A}ST-;j2BlsJV=F=^G=`BKq1f069Yp|4g)5~7o@r|<28Z-KnbfItmUl42fYQm&4p>xX z@@BB?XIIAy>&YAglZn(`6A9jrvFAmzlp=<4R>M*LI)XG$J|(kX7l{S48(S4B&%M(`d`(Y(-(Z?W&r&RV`y z?uU0(B;pNTmAX3$+>;LS3G`?iRHlurQN;b{ z9v4;?PEik-1C2>fNVeqGaJO(V7CTC2s176r_E3N*aORA3@LYmgqlEO`l80fzB^eeg z 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ⅈ2UqjmeP-$`Z8!}>wIR} z8>OqVetdeAA1oo6?T1ZU5osTi{Bg&h7JSDI$`G_T)#fDQ9=d`dX26*~fB8GV&deC- zQ(H@kD|kbi9eG8+jQ{)gss2K#$X(?Kzf+7jHi$o46C2_AOggn;(74uNp3k>vZYY$o zg$S?Sr0o~e^*qU1V3Y(4H(+)+mMpsnWE8rL!Ha#4R3gOWEWREot!X|NlKz~m{~V?g z7~MOAeGjRr*B`0q&JSPnhxv~kVM~6|sG{nuC_DlbEQ+=TOAECD_07Q$oJif0(Rh*h zVIoU}g(OG>ADqEJMJ}_eU5a>{z{FP&I!a38%h{rv7oaSD{DP*==_AMSnbxLMFF7Ih zVqp=jdaHG(wSR;&QU$$R+}ex2A1}Y6F?Yp}1*X(`5laT+^q;_w2q(9{0P1*dD>zHD zFn80#X$YmK1iHPH<4x|UY{={|z ze~@uYVKNF0V$2ntU_Xw5pl(z$SZ>Us-Zt;-xLT{C^M%xh7HV@V2nl9RVEf8oV#V$7 z5fc6e@yB3Ny~YCp1a0H_ejr$_!3o6AsHS2Gs-`C2D9j;8UG3YApuW^tYy`#E>wYl% znRXx-gp+$QqLd~W4ZMJ#m*g5qaD?NX$J{FGl%i+rdrmDfhZB7mf!v7?p`e2%o@%Xz zN@`$x**LQ#fj|LYfZtTn;A?h=mY;`L=KU4AiMHFN9ydeS( zs?iv^PGy&L+V#hb9{%gO63PpTQp-A#oV{CHjQi`xdsU4CtJN}I*#MAm(i&grPS=zz zb+EKmUp^C&qExqO#W8=aZTmUxeQifzduG8{%i+}mcIRIZMXxwq07WcDW?TCbZaa?y zcK=9b17509bqFmFn>lViyG>9w7}--&F~q?p=hn@NpJ{tpXBjQnI{;7xb6hLGvx;LbIxX}4Jj#tEZneNE{OLQqH<{XGvq zbHRJhle7t@PN=$qp3Fy!MmVL9EIPn?CJ-Wyt>eHXNYBCK74N5QtADAn#?8{sEuX>B z`dh{vlxBH_K<%DU0F8!eybrA6mg&+)QAVv4 zFM!?$sPvG#0Ra_T!|G%hmY&g2!@F~cRa2wKS0E^H2BwQmXb9?P4Fm-3iZg36-?KQ( zXZJPRC(8GoOiI^<<*6P%d3o7^aQG_UaQcs6V1A8 z2XjiNr7cRLKK~yEStIIs&PZadDO@GdMviPJ_MY(VLgM0UY2_Poa`I^!4oe}kq*gF4|hskrgToRBWr^WPwZLXZ}SgD0WI6=OF>$= z9`Tx{LAcZJI1Kn!{JlcEAs41rezZ3bI5LuRMuE1|7p`Jq^@DEUP}YIpIsgFPZ%xtk z$%H7Y2e|n}E6NuJ!7ikFsNz`(-Cw8ci^V;T2)xo@TnA!6KT{6S=Rjc-SyM@Q13?>z z`@4ABK*E8dD(7CN_{rT@hk_Y~5v5lsQ0L|j*i^tfDSOvm6?RD|KPvcFM5-M$yX;Su*s%gXDn_JRu&IeinOeYt)G1lO7_E1u-E z7_G(`ZW-rF)g4e`@RH*8x4W6T>0`k$VjK{4^A@Q{^+vRx6%tQrjZ0HW<;sS2$#iI) zUStC%MNv@sq5Zkab=j9Bq@{FD|yi{l)YBjPXwu3Y8 zf|yJCGB-+F!&+p-U}@WoLbUvz_)_qEJ$0A*IAgo zhHPj(FJqAJoF))lM$syVV$Xiw3DJNH%dbF&N}Y}h#!RG@R_Ebd^&FV&)pcA7Iq_iN z66ciRL(b+Qk2O|y9}O9VQoyX5p&|yinU@~iOⅈF@Q42eaFi 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 *n#N**ycaJS0n5L8gZ1iQ4CGM0F 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 Xe;2J~%8h7-F0gU#_;jvpq1rTR02Yh? literal 0 HcmV?d00001 diff --git a/MikroNUC/20260627/20260627232001-Config.rsc b/MikroNUC/20260627/20260627232001-Config.rsc new file mode 100644 index 0000000..a46b8cb --- /dev/null +++ b/MikroNUC/20260627/20260627232001-Config.rsc @@ -0,0 +1,4861 @@ +# 2026-06-27 23:20:03 by RouterOS 7.23.1 +# system id = NmJcEM+8XAP +# +/caps-man channel +add band=2ghz-g/n extension-channel=disabled frequency=2422 name=2G-3 \ + reselect-interval=20m save-selected=yes +add band=5ghz-a/n/ac extension-channel=XXXX frequency=5660 name=5G-5660 \ + save-selected=yes +add band=5ghz-a/n/ac extension-channel=XXXXXXXX frequency=5160,5200,5280 \ + name=5G-5160-5280 reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5180 name=5G-36 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5200 name=5G-40 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5220 name=5G-44 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5240 name=5G-48 \ + reselect-interval=30m save-selected=yes +add band=2ghz-g/n extension-channel=disabled frequency=2442 name=2G-7 \ + reselect-interval=20m save-selected=yes +add band=2ghz-g/n extension-channel=disabled frequency=2462 name=2G-11 \ + reselect-interval=20m save-selected=yes +/interface bridge +add name=Bridge-DOC +add name=Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] disable-running-check=no name=ether2 +/interface veth +add address=172.18.20.2/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ + gateway=172.18.20.1 gateway6="" name=docker-awg-veth +/caps-man datapath +add bridge=Bridge-LAN client-to-client-forwarding=yes local-forwarding=yes \ + name=xs-DataPath +add bridge=Bridge-LAN client-to-client-forwarding=yes local-forwarding=yes \ + name=DataPath +/caps-man security +add authentication-types=wpa2-psk encryption=aes-ccm group-encryption=aes-ccm \ + group-key-update=30m name=xs-Sec +add authentication-types=wpa2-psk encryption=aes-ccm group-encryption=aes-ccm \ + group-key-update=30m name=WPA2 +/caps-man configuration +add channel.band=2ghz-b/g/n country=no_country_set datapath=xs-DataPath mode=\ + ap name=xs-2G rx-chains=0,1,2,3 security=xs-Sec ssid=vados tx-chains=\ + 0,1,2,3 +add channel.band=5ghz-a/n/ac country=no_country_set datapath=xs-DataPath \ + installation=any mode=ap name=xs-5G rx-chains=0,1,2,3 security=xs-Sec \ + ssid=vados5g tx-chains=0,1,2,3 +add channel.band=2ghz-b/g/n .control-channel-width=20mhz .extension-channel=\ + XX .frequency=2422,2442,2462 .reselect-interval=20m country=belarus \ + datapath=DataPath datapath.client-to-client-forwarding=yes \ + .local-forwarding=yes hw-protection-mode=rts-cts installation=any name=2G \ + rx-chains=0,1,2,3 security=WPA2 ssid=vados tx-chains=0,1,2,3 +add channel.band=5ghz-a/n/ac .control-channel-width=20mhz .extension-channel=\ + XXXX .frequency=5180,5200,5220,5240,5260 .reselect-interval=20m \ + .skip-dfs-channels=yes country=belarus datapath=DataPath \ + datapath.client-to-client-forwarding=yes .local-forwarding=yes \ + hw-protection-mode=rts-cts installation=any name=5G security=WPA2 ssid=\ + vados5g +/disk +add slot=ram tmpfs-max-size=100000000 type=tmpfs +/interface list +add include=dynamic,static name=LAN +add exclude=LAN name=WAN +add exclude=LAN include=WAN name=Internet +/interface wireless security-profiles +set [ find default=yes ] supplicant-identity=MikroMIC +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=P1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +/ip pool +add name=dhcp ranges=10.30.30.150-10.30.30.200 +/routing table +add disabled=no fib name=r_to_vpn +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=test owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \r\ + \n#:local ScriptName [ :jobname ];\r\ + \n:local expSrc;\r\ + \n:local FileName;\r\ + \n:local FilePath;\r\ + \n:local DirPath \"tmpfs/\";\r\ + \n:global WaitForFile;\r\ + \n:global IfThenElse;\r\ + \n\r\ + \n:foreach Script in=([ /system/script find where name~\"Amster-GlobalConf\ + *\" ]) do={\r\ + \n:local ScriptVal [ /system/script/get \$Script ];\r\ + \n\r\ + \n:local expName [ (\$ScriptVal->\"name\") ];\r\ + \n#[/system/script get \$expScript name];\r\ + \n:delay 2s;\r\ + \n\r\ + \n:set expSrc [/system/script print where name=\$expName];\r\ + \n/system/script print where name=\$expName;\r\ + \n#[:put [/system/script get \$expScript source]];\r\ + \n:put [\$expSrc];\r\ + \n:delay 2s;\r\ + \n:set FileName \$expName;\r\ + \n:set FilePath (\$DirPath . \$FileName);\r\ + \n\r\ + \n#:log warning \"\\n----------------------\\n\\\$expSrc = \$expSrc\\n____\ + ______________________________\";\r\ + \n:log info \"\\n\\\$FileName = '\$FileName'\";\r\ + \n:log info \"\\n\\\$FilePath = \$FilePath\";\r\ + \n#:log warning {/system/script/get source=[/system/script/get \$expScript\ + \_source];};\r\ + \n\r\ + \n#\$[/system script get [/system script find name=\"\$FileName\"] source]\ + \r\ + \n\r\ + \n#:local gettingScript \"\$FileName\";\r\ + \n#:execute script=\"[[:parse \\\"[:parse { :put (\"\$[/system script get \ + [/system script find name=\$FileName] source]\"); } \\\"]]\"; \\\r\ + \n\r\ + \n#:execute script={:put \"[:parse \\\"[:parse [/system/script get [/syste\ + m/script find name=\$gettingScript] source];\\\"]]\";} \\\r\ + \n# file=(\$FilePath . \".rsc\\00\");\r\ + \n:do {\r\ + \n:local fName (\$FilePath . \".rsc\");\r\ + \n#:delay 3s;\r\ + \n#/file add name=\$fName;\r\ + \n:put [:tostr [\$expSrc]];\r\ + \n/file set \$fName contents=[:put [\$expSrc]];\r\ + \n:delay 3s;\r\ + \n\$WaitForFile \$fName;\r\ + \n(\$FilePath . \".rsc\");\r\ + \n#:delay 2s;\r\ + \n\r\ + \n} on-error={\r\ + \n:log error \"\\nERROR \\\$FilePath = \$FilePath\";\r\ + \n}\r\ + \n#\$WaitForFile (\$FilePath . \".rsc\");\r\ + \n#:execute script={ :put [/system/script get [:put \$FileName] source]; }\ + ;\r\ + \n#/system/script export \$Sscript file=\$FilePath;\r\ + \n#/system/script/export [:put [/system/script/get \$expScript source]] fi\ + le=\$FilePath;\r\ + \n#:execute script={ :put [/system/script/get \$expScript source]; } \\\r\ + \n\r\ + \n#:log warning \"\\n\\\$expScript = \$expScript\";\r\ + \n# \\\r\ + \n# file=(\$FilePath . \".rsc\\00\");\r\ + \n#script={:put [/system/script/get \$FileName source];} file=(\$FilePath\ + \_. \".rsc\\00\");\r\ + \n#/system script export \$src file=(\$FilePath . \$FileName);\r\ + \n}\r\ + \n\r\ + \n:log warning \"\\nComplete!\";\r\ + \n\r\ + \n # :execute script={ :put [ /system/script/get Amster-GlobalConfig sou\ + rce ]; } \\\r\ + \n # file=(\$FilePath . \".conf\\00\");\r\ + \n # \$WaitForFile (\$FilePath . \".conf\");\r\ + \n # :onerror Err {\r\ + \n # /tool/fetch upload=yes url=(\$BackupUploadUrl . \"/\" . \$FileName\ + \_. \".conf\") \\\r\ + \n # user=\$BackupUploadUser password=\$BackupUploadPass src-path=(\ + \$FilePath . \".conf\");\r\ + \n # :set ConfigFile [ /file/get (\$FilePath . \".conf\") ];\r\ + \n # :set (\$ConfigFile->\"name\") (\$FileName . \".conf\");\r\ + \n " +add dont-require-permissions=no name=test1 owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n#:local runningVer [:find [/system/resource/get version] \"(\"];\r\ + \n\r\ + \n:local runningChannel;\r\ + \n:local runningVersion;\r\ + \n:local ParseCustom;\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n \r\ + \n:global runningChannel [\$ParseCustom [/system/resource/get version] \"(\ + \" \")\" 1];\r\ + \n:log warning [\$runningChannel];\r\ + \n:set runningVersion [\$ParseCustom [/system/resource/get version] \" \" \ + \")\" 2];\r\ + \n:log warning [\$runningVersion];\r\ + \n\r\ + \n\r\ + \n\r\ + \n# :if ([:len \$open] = 0) do={\r\ + \n# :log error \"\$SMP Could not extract installed OS channel from vers\ + ion string: `\$runningOsAndChannel`.\";\r\ + \n# :error \"\$SMP error, check logs\";\r\ + \n# }\r\ + \n# :local rest [:pick \$runningOsAndChannel (\$open+1) [:len \$runningOs\ + AndChannel]];\r\ + \n# :local close [:find \$rest \")\"];\r\ + \n# :local channel [:pick \$rest 0 \$close];\r\ + \n# :return \$channel;\r\ + \n#}" +add dont-require-permissions=no name=01-Amster-Init-Script owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# Amster Initial Script\r\ + \n#\r\ + \n#:global GlobalEnvRemove true; /system/script {run Amster-GlobalEnvRemov\ + e; };\r\ + \n#:delay 1s;\r\ + \n:#global ReloadGlobal true; \r\ + \n\r\ + \n:global AmScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global defOwner \"vados\";\r\ + \n:global AmFirstRun;\r\ + \n\r\ + \n:set AmFirstRun do={\r\ + \n :global AmScriptsUrl;\r\ + \n :global defOwner;\r\ + \n #:global ParseKeyValueStore;\r\ + \n #:local AmUpdCRLF true;\r\ + \n #:local IfThenElse;\r\ + \n #:set IfThenElse do={:if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1\ + \_] = true) do={:return \$2}; :return \$3}\r\ + \n #/certificate/settings/set builtin-trust-store=fetch;\r\ + \n #/tool/fetch \"\$scriptsUrl/certs/Root-YE.pem\" dst-path=\"root-ye.p\ + em\";\r\ + \n #/certificate/import file-name=\"root-ye.pem\" passphrase=\"\";\r\ + \n # For basic verification we rename the certificate and print it by f\ + ingerprint. Make sure exactly this one certificate (\"Root-YE\") is shown.\ + \r\ + \n #/certificate/set name=\"Root-YE\" [ find where common-name=\"Root Y\ + E\" ];\r\ + \n #/certificate/print proplist=name,fingerprint where fingerprint=\"e1\ + 4ffcad5b0025731006caa43a121a22d8e9700f4fb9cf852f02a708aa5d5666\";\r\ + \n #:log info \"\\nAmScriptsUrl = \$AmScriptsUrl\";\r\ + \n :local Scripts {\r\ + \n \"Amster-GlobalConfig\"\r\ + \n \"Amster-GlobalFunc\";\r\ + \n# \"Amster-SFTP-backup\"\r\ + \n# \"Amster-BkpEmail-and-upd\";\r\ + \n };\r\ + \n# /system/script/set owner=(\$ScriptVal->\"name\") \\\r\ + \n# source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRLF \$S\ + ourceNew ] \$Script;\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$defOwner source=([ /too\ + l/fetch (\"\$AmScriptsUrl\" . \$Script . \".rsc\") output=user as-value ]-\ + >\"data\");\r\ + \n /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$\ + Script;\r\ + \n };\r\ + \n /system/script { run Amster-GlobalConfig; run Amster-GlobalFunc; }\r\ + \n}\r\ + \n:global AmUpdRun;\r\ + \n:set AmUpdRun do={\r\ + \n #:local UpdScript [ :tostr \$1 ];\r\ + \n #:global ParseKeyValueStore;\r\ + \n :global AmScriptsUrl;\r\ + \n :global defOwner;\r\ + \n :local Scripts {\r\ + \n# \"Amster-GlobalConfig\"\r\ + \n# \"Amster-GlobalFunc\"\r\ + \n# \"Amster-GlobalRemove\"\r\ + \n \"Amster-backup-SFTP\"\r\ + \n \"Amster-SFTP-backup\"\r\ + \n \"Amster-BkpEmail-and-upd\"\r\ + \n \"Amster-TG-Bot\"\r\ + \n \"Amster-TG-Notification\";\r\ + \n };\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :put \"updating \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$defOwner source=([ /too\ + l/fetch (\"\$AmScriptsUrl\" . \$Script . \".rsc\") output=user as-value ]-\ + >\"data\");\r\ + \n /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$\ + Script;\r\ + \n };\r\ + \n# /system/script/add name=\$Script owner=\$AmOwner source=([ /tool/fe\ + tch check-certificate=yes-without-crl (\"\$AmScriptsUrl\" . \$Script . \".\ + rsc\") output=user as-value ]->\"data\"); };\r\ + \n}\r\ + \n\r\ + \n\$AmFirstRun;\r\ + \n#\$AmUpdRun;\r\ + \n\r\ + \n#\$setUpdExist;\r\ + \n#:global setUpdExist;\r\ + \n#:global ParseKeyValueStore;\r\ + \n#:set setUpdExist do={\r\ + \n#:do {\r\ + \n#:global ParseKeyValueStore;\r\ + \n# :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vad\ + os\\r\?\\n#comment=*\" ] do={\r\ + \n# :local ScriptVal [ /system/script/get \$Script ];\r\ + \n# :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"#comment\"\ + ) ];\r\ + \n# :local scriptName (\$ScriptVal->\"name\");\r\ + \n#:log warning (\"\\n\\\$scriptName = \". \$scriptName);\r\ + \n#: log warning (\"\\n\\\$ScriptInfo = \". \$ScriptInfo);\r\ + \n# }\r\ + \n#} on-error={}\r\ + \n#}\r\ + \n#\$name;\$owner;\$policy;\$dont-require-permissions;\$last-started;\$run\ + -count;\$source;\$invalid;\$comment;\$.id;\$.nextid;\$.dead;\$.about;\r\ + \n#;(evl / (evl /docommand=;(evl / (evl /foreachcounter=\$Script;do=;(evl \ + / (evl /localname=\$ScriptVal;value=(evl (evl /system/script/getnumber=\$S\ + cript))) (evl /localname=\$ScriptInfo;value=(evl (<%% \$ParseKeyValueStore\ + \_(> \$ParseKeyValueStore);(-> \$ScriptVal comment)))) (evl /localname=\$s\ + criptName) (evl /setname=\$scriptName;value=(-> #\$ScriptVal name)) (evl /\ + log/errormessage=(. \r\ + \n# \$ ScriptInfo = \$ScriptInfo)));in=(evl (evl /system/script/findwhere\ + =\$name;\$owner;\$policy;\$dont-require-permissions;\$last-started;\$run-c\ + ount;\$source;\$invalid;\$comment;\$.id;\$.nextid;\$.dead;\$.about;(~ \$so\ + urce (. ^#!rsc by Vados \r\ + \n# \? \r\ + \n#));5))));on-error=;(evl /)))\r\ + \n" +add dont-require-permissions=no name="Download cAP's Packages" owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# +------------------------------+\r\ + \n# | |\r\ + \n# | Mikrotik RouterOS Scripts |\r\ + \n# | _Download cAP's Packages_ |\r\ + \n# | |\r\ + \n# +------------------------------+\r\ + \n# https://github.com/sebastian13/mikrotik-routeros-scripts\r\ + \n#\r\ + \n\r\ + \n# Set a directory path providing the required space\r\ + \n# Add a microSD card https://wiki.mikrotik.com/wiki/Manual:System/Disks\ + \r\ + \n# or setup a RAM-Disk via '/disk/add type=tmpfs tmpfs-max-size=20M slot=\ + ram'\r\ + \n:local dir \"/tmpfs/capsman-packages\";\r\ + \n\r\ + \n\r\ + \n# Set Package Path if required, set policy to none if using 'upgrade-cap\ + s' script\r\ + \n/interface/wifi/capsman/set package-path=\$dir upgrade-policy=none;\r\ + \n/caps-man/manager/set package-path=\$dir upgrade-policy=none;\r\ + \n#require-same-version;\r\ + \n\r\ + \n:local installed [/system package get value-name=version [find where nam\ + e=\"routeros\"]]\r\ + \n\r\ + \n# Delete old downloads\r\ + \n# /file/remove [ find type=package name~\"capsman*\" ]\r\ + \n\r\ + \n# Starting from RouterOS version 7.13, drivers for older wireless and 60\ + GHz interfaces are\r\ + \n# part of the separate \"wireless\" package. The existing \"wifiwave2\" \ + package has been divided\r\ + \n# into distinct packages: \"wifi-qcom\" and \"wifi-qcom-ac\".\r\ + \n# RouterOS >=7.12 is required to upgrade to 7.13.\r\ + \n# https://forum.mikrotik.com/viewtopic.php\?t=202423\r\ + \n\r\ + \n:foreach architecture in={ \"arm\";\r\ + \n# \"arm64\";\r\ + \n \"x86_64\";\r\ + \n \"mipsbe\"} do={\r\ + \n :foreach package in={ \"routeros\";\r\ + \n# \"wifi-qcom-ac\";\r\ + \n# \"wifi-qcom\";\r\ + \n \"container\";\r\ + \n \"wireless\"} do={ :do {\r\ + \n :put \"\"\r\ + \n :put \"Download \$package \$installed for \$architecture\"\r\ + \n /tool fetch mode=https \\\r\ + \n url=\"https://download.mikrotik.com/routeros/\$installed/\$packa\ + ge-\$installed-\$architecture.npk\" \\\r\ + \n dst-path=\"\$dir/\$package-\$installed-\$architecture.npk\"\r\ + \n } on-error={ :put \"Error downloading the file. On a 404, note t\ + hat the package may not exist for the specified architecture!\" }\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Script for setup routeros script system" \ + dont-require-permissions=no name=AM-setup owner=AM-setup policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-setup\r\ + \n# Script comment: Script for setup routeros script system\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# :local ScriptName [ :jobname ];\r\ + \n# Additional commands:\r\ + \n#\r\ + \n# For scripts:\r\ + \n#:global NewScript \"script_name\"; \r\ + \n#:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n#/system/script/add name=\$NewScript owner=\$NewScript source=([/tool/fe\ + tch check-certificate=yes-without-crl (\$GlobalScriptsUrl . \$ScriptAdd . \ + \".rsc\") output=user as-value ]->\"data\");\r\ + \n#:global NewScript (a);\r\ + \n#:global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n#\r\ + \n# For run from terminal:\r\ + \n#/system/script/add name=AM-setup owner=AM-Setup source=([/tool/fetch ch\ + eck-certificate=yes-without-crl \"https://ros.vados.ru/AM-setup.rsc\" outp\ + ut=user as-value ]->\"data\");\r\ + \n#\r\ + \n\r\ + \n:global ScriptUpdatesCRLF \"LF\";\r\ + \n#:if (\$ScriptUpdatesCRLF != false) do={\r\ + \n# :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vad\ + os\" ] do={\r\ + \n# if (\$ScriptUpdatesCRLF = true) do={\r\ + \n# /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$S\ + cript;\r\ + \n# } else={\r\ + \n# /system/script/set source=[ :tolf [ get \$Script source ] ] \$Scr\ + ipt;\r\ + \n# }\r\ + \n# }\r\ + \n#}\r\ + \n\r\ + \n# /import verbose=no \$ScriptName\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global SetupScript [ :jobname ];\r\ + \n:global RemoveMe true;\r\ + \n:global RunOnce (a);\r\ + \n:global InitSetup true;\r\ + \n:global tmpfs false;\r\ + \n\r\ + \n{\r\ + \n :local RmMe [:tobool \$1];\r\ + \n\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SetupScript;\r\ + \n :global RemoveMe;\r\ + \n :global InitSetup;\r\ + \n :global tmpfs;\r\ + \n\r\ + \n :local UrlSuffix \$Identity;\r\ + \n :local UrlDir \"certs/\";\r\ + \n :local CertUrl (\$GlobalScriptsUrl . \$UrlDir . \$UrlSuffix .\"/\"); \ + \r\ + \n :local CertCommonName \"Root YE\";\r\ + \n :local CertFileName \"Root-YE.pem\";\r\ + \n :local CertFingerprint \"e14ffcad5b0025731006caa43a121a22d8e9700f4fb9c\ + f852f02a708aa5d5666\";\r\ + \n\r\ + \n :if (\$SetupScript = false) do={\r\ + \n :global SetupScript \"AM-setup\";\r\ + \n }\r\ + \n :if (\$RemoveMe != false) do={\r\ + \n :set RemoveMe true;\r\ + \n }\r\ + \n\r\ + \n :log warning (\"\\n\\\$GlobalScriptsUrl = \" . \$GlobalScriptsUrl);\r\ + \n \r\ + \n\r\ + \n :if (!(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" ||\ + \_\\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CertComm\ + onName ] ] > 0)) do={\r\ + \n :put \"Importing certificate...\";\r\ + \n /tool/fetch (\$CertUrl . \$CertFileName) dst-path=\$CertFileName\ + \_as-value;\r\ + \n :delay 1s;\r\ + \n /certificate/import file-name=\$CertFileName passphrase=\"\";\r\ + \n /certificate/set name=\"Root-YE\" [ find where common-name=\"Roo\ + t YE\" ];\r\ + \n :delay 1s;\r\ + \n };\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ + ] != 1) do={\r\ + \n :error \"Something is wrong with your certificates!\";\r\ + \n };\r\ + \n\r\ + \n:local MkTmpfs do={\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\"The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\"Try to removing directory 'tmpfs'.\");\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/remove tmpfs;\r\ + \n :return true;\r\ + \n } delay=100ms max=10;\r\ + \n } on-error={ }\r\ + \n# \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/g\ + et total-memory ] / 3);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get tmpfs;\r\ + \n :return true;\r\ + \n } delay=222ms max=10;\r\ + \n } on-error={ }\r\ + \n } do={\r\ + \n :log warning (\"Creating disk of type tmpfs failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n# :return true;\r\ + \n}\r\ + \n:if (\$tmpfs = true) do={\r\ + \n :put \"Tmpfs variable is true. Checking for tmpfs/scripts directory...\ + \";\r\ + \n :if ([/file find name=\"tmpfs/scripts\"] != \"\") do={\r\ + \n :log info (\$0 . \"Directory tmpfs/scripts exsist.\");\r\ + \n :return \$true;\r\ + \n } else={\r\ + \n :log warning (\$0 . \"Directory tmpfs/scripts does't exsist.\");\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :log error (\$0 . \"Directory tmpfs is not created!\");\r\ + \n :return false;\r\ + \n } else={\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=/tmpfs/scripts;\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get /tmpfs/scripts;\r\ + \n :return true;\r\ + \n } delay=100ms max=10;\r\ + \n } on-error={ }\r\ + \n } do={\r\ + \n :log warning (\$0 . \"Making directory 'scripts' failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n# :return true;\r\ + \n# [ /file/get \$FileName ]\r\ + \n }\r\ + \n# :log error (\$0 . \"Directory tmpfs/scripts does not exsist. Remove\ + \_global variable tmpfs!\");\r\ + \n# :global tmpfs (a);\r\ + \n# return false;\r\ + \n }\r\ + \n}\r\ + \n :put \"Renaming AM-GlobalConfig, if exists...\";\r\ + \n :local ConfOldName (\"AM-GlobalConfig-\" . [ /system/clock/get date ] \ + . [ /system/clock/get time ] . \".rsc\");\r\ + \n /system/script/set name=\$ConfOldName [ find where name=\"AM-GlobalCon\ + fig\" ];\r\ + \n :foreach Script in={ \"AM-GlobalConfig\"; \"AM-GlobalFunc\" } do={\r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$Script source=([ /tool/fetc\ + h check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \ + \".rsc\") output=user as-value ]->\"data\");\r\ + \n \r\ + \n /system/script run \$Script;\r\ + \n :delay 2s;\r\ + \n };\r\ + \n\r\ + \n :local Script \"mod/AM-Certs-By-Ident\";\r\ + \n \r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$Script source=([ /tool/fetch \ + check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".\ + rsc\") output=user as-value ]->\"data\");\r\ + \n /system/script run \$Script;\r\ + \n :global tmpAddCerts;\r\ + \n :while ([ \$tmpAddCerts ] = true) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n :delay 1s;\r\ + \n :put \"Removing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ + ] > 0) do={\r\ + \n :put \"Renaming certificate by its common-name...\";\r\ + \n :global CertificateNameByCN;\r\ + \n \$CertificateNameByCN \$CertFingerprint;\r\ + \n };\r\ + \n\r\ + \n :if (\$RemoveMe = true) do={\r\ + \n :put \"Add Scheduler for remove this script...\";\r\ + \n :local OnEvent (\":delay 30s;\\n\" . \"/system/script/remove [ find \ + where name=\\\"\$SetupScript\\\" ];\\n\" . \\\r\ + \n \":delay 2s;\\n\" . \"/system/scheduler/remove [ find where name=\\\ + \"_RemoveSetup\\\" ];\\n\" . \\\r\ + \n \":delay 2s;\\n\" . \":global RemoveMe (a);\\n\");\r\ + \n :local Comment \"_RemoveSetup tmp scheduler for remove setup script.\ + \";\r\ + \n /system/scheduler/add name=\"_RemoveSetup\" comment=\$Comment start-\ + time=startup interval=30s on-event=\$OnEvent;\r\ + \n :log warning (\$0 . \"\\nI've done everything, and now I'm tired..\ + . I'm leaving.\\nThere will be an error below, this is normal.\");\r\ + \n }\r\ + \n :delay 1;\r\ + \n :put \"Loading configuration and functions...\";\r\ + \n :do { \r\ + \n :global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n :put \"Normal removing temporary global environment variables.\";\ + \r\ + \n :global SetupScript (a);\r\ + \n :global InitSetup (a);\r\ + \n :global RemoveMe (a);\r\ + \n } on-error={\r\ + \n :local ErrorMsg \"Loading configuration and functions error!\";\r\ + \n :log error (\$0 . \$ErrorMsg . :error);\r\ + \n :error \$ErrorMsg;\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix (a);\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n#:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\r\ + \n# \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/700/f14f095d\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:03 22.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$0 . \" Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Hostname\" \$Identity ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location\" (\$Snmp->\"location\") ] . \"\\n\") ]\ + \_. \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact\" (\$Snmp->\"contact\") ] . \"\\n\") ] .\ + \_\\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n :log warning (\$0 . \"This system has low free flash space but \" . \ + \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n :log warning (\$0 . \"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log info (\$0 . \"There are \" . \$CertCount . \" Certificates with\ + \_CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" \ + || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\ + \r\ + \n [ :len [ /certificate/builtin/find where common-name=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n :log warning (\$0 .\" No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={ :set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]; }\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={ :set Path [ :pick \$Path 1 [ :le\ + n \$Path ] ]; }\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={ :set Path [ \ + :pick \$Path 0 ([ :len \$Path ] - 1) ]; }\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\$0 . \" Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Creating disk of type tmpfs failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log debug (\$0 . \" ... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n :log warning (\$0 . \" Making directory '\" . \$Path . \"' failed: \ + \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log error (\$0 . \" No valid RouterOS version: \" . \$Required);\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n :log warning (\$0 . \"No symbol available for name '\" . \$Name . \"\ + '!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\r\ + \n\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n\r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Every Day Set Global Environment Variables\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\r\ + \n#\r\ + \n#root.mnuc.backuper\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n#:local Script AM-GlobalConfig;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n#/usb1/mikro_bak_rsa.pub\r\ + \n#:local FetchFile AM-DOHCert.rsc\r\ + \n\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/tmp/\";\r\ + \n:global MkDir;\r\ + \n\r\ + \n:local FetchFile Binary.backup\r\ + \n:local localDir \"[usb1]/scripts/\";\r\ + \n\r\ + \n\$MkDir \$localDir;\r\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\r\ + \n" +add dont-require-permissions=yes name=MkTmpfs owner=vados policy=\ + ftp,read,write,policy,test,sniff,sensitive source=\ + ":global MkDir;\r\ + \n\r\ + \n\$MkDir /usb1/tmpfs;" +add dont-require-permissions=no name=CreateContainer owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local contIF \"veth1\";\r\ + \n:local contIP \"10.10.10.10/24\";\r\ + \n:local contGW \"10.10.10.1\";\r\ + \n#/interface/veth/add name=\$contIF address=\$contIP gateway=\$contGW;\r\ + \n:local contBridgeIF \"Bridge-DOC\";\r\ + \n:local contBridgeIP \"10.10.10.1/24\";\r\ + \n/interface/bridge/add name=\$contBridgeIF;\r\ + \n/ip/address/add address=\$contBridgeIP interface=\$contBridgeIF;\r\ + \n/interface/bridge/port/add bridge=\$contBridgeIF interface=\$contIF;\r\ + \n/container/config/set ram-high=768M registry-url=https://registry-1.dock\ + er.io tmpdir=sata1/tmp\r\ + \n" +add dont-require-permissions=no name=carkeeperbot owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ + container/mounts/add list=carkeeper_configs/.profile src=sata1/carkeeper/c\ + onfigs/.profile dst=/root/.ashrc;\r\ + \n/container/mounts/add list=carkeeper_configs/php.ini src=sata1/carkeeper\ + /configs/php.ini dst=/etc/php82/php.ini;\r\ + \n#/container/mounts/add list=carkeeper_configs src=sata1/carkeeper/config\ + s dst=/configs;\r\ + \n/container/mounts/add list=carkeeper_app src=sata1/carkeeper/app dst=/ap\ + p;\r\ + \n/container/mounts/add list=carkeeper_scripts src=sata1/carkeeper/scripts\ + \_dst=/scripts;\r\ + \n/container/mounts/add list=carkeeper_configs/sshd_config src=sata1/carke\ + eper/configs/sshd_config dst=/etc/ssh/sshd_config;\r\ + \n\r\ + \n/container/mounts/add list=carkeeper_tmp src=sata1/carkeeper/tmp dst=/va\ + r/tmp;\r\ + \n/container/mounts/add list=carkeeper_sync src=sata1/carkeeper/sync dst=/\ + var/sync;\r\ + \n" +add comment="Enable or disable ip addresses based on bridge port state" \ + dont-require-permissions=no name=mod/AM-IPbridge owner=mod/AM-IPbridge \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: mod/AM-IPbridge\r\ + \n# Script comment: Enable or disable ip addresses based on bridge port st\ + ate\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n# Add this Script scheduler\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n:log warning (\"SystemScheduler for script: \" . \$ScriptName . \" is NO\ + T SET! Fix It Now!\");\r\ + \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ + \n:local Comment \"Every Day Check For Fake Bridges\";\r\ + \n/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=sta\ + rtup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:foreach Bridge in=[ /interface/bridge/find ] do={\r\ + \n :local BrName [ /interface/bridge/get \$Bridge name ];\r\ + \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName ] ] > \ + 0) do={\r\ + \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName and \ + inactive=no ] ] = 0) do={\r\ + \n /ip/address/disable [ find where !dynamic interface=\$BrName ];\r\ + \n } else={\r\ + \n /ip/address/enable [ find where !dynamic interface=\$BrName ];\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Use Telegram to chat with your Router and send commands" \ + dont-require-permissions=no name=mod/AM-TG-Bot owner=mod/AM-TG-Bot \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: mod/AM-TG-Bot\r\ + \n# Script comment: Use Telegram to chat with your Router and send command\ + s\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ + delay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n :global Identity;\r\ + \n :global TelegramChatActive;\r\ + \n :global TelegramChatGroups;\r\ + \n :global TelegramChatId;\r\ + \n :global TelegramChatIdsTrusted;\r\ + \n :global TelegramChatOffset;\r\ + \n :global TelegramChatRunTime;\r\ + \n :global TelegramMessageIDs;\r\ + \n :global TelegramRandomDelay;\r\ + \n :global TelegramTokenId;\r\ + \n\r\ + \n :global CertificateAvailable;\r\ + \n :global EitherOr;\r\ + \n :global EscapeForRegEx;\r\ + \n :global FileExists;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global LogPrintVerbose;\r\ + \n :global MAX;\r\ + \n :global MIN;\r\ + \n :global MkDir;\r\ + \n :global RandomDelay;\r\ + \n :global RmDir;\r\ + \n :global ScriptLock;\r\ + \n :global SendTelegram2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global WaitForFile;\r\ + \n :global WaitFullyConnected;\r\ + \n\r\ + \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n \$WaitFullyConnected;\r\ + \n\r\ + \n :if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) \ + do={\r\ + \n /system/scheduler/add start-time=startup interval=30s name=\$ScriptN\ + ame on-event=\"/system/script/run \$ScriptName;\" comment=\"Telegram Chat \ + Bot\";\r\ + \n }\r\ + \n :if ([ :typeof \$TelegramChatOffset ] != \"array\") do={\r\ + \n :set TelegramChatOffset { 0; 0; 0 };\r\ + \n }\r\ + \n :if ([ :typeof \$TelegramRandomDelay ] != \"num\") do={\r\ + \n :set TelegramRandomDelay 0;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Go Daddy Root Certificate Authority - \ + G2\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$ScriptName (\"Downloading required certificate \ + failed.\");\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n \$RandomDelay \$TelegramRandomDelay;\r\ + \n\r\ + \n :local Data false;\r\ + \n :for I from=1 to=4 do={\r\ + \n :if (\$Data = false) do={\r\ + \n :onerror Err {\r\ + \n :set Data ([ /tool/fetch check-certificate=yes-without-crl outpu\ + t=user \\\r\ + \n (\"https://api.telegram.org/bot\" . \$TelegramTokenId . \"/get\ + Updates\?offset=\" . \\\r\ + \n \$TelegramChatOffset->0 . \"&allowed_updates=%5B%22message%22%\ + 5D\") as-value ]->\"data\");\r\ + \n :set TelegramRandomDelay [ \$MAX 0 (\$TelegramRandomDelay - 1) ]\ + ;\r\ + \n } do={\r\ + \n :if (\$I < 4) do={\r\ + \n \$LogPrint debug \$ScriptName (\"Fetch failed, \" . \$I . \". \ + try: \" . \$Err);\r\ + \n :set TelegramRandomDelay [ \$MIN 15 (\$TelegramRandomDelay + 5\ + ) ];\r\ + \n :delay ((\$I * \$I) . \"s\");\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if (\$Data = false) do={\r\ + \n \$LogPrint warning \$ScriptName (\"Failed getting updates.\");\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local JSON [ :deserialize from=json value=\$Data ];\r\ + \n :local UpdateID 0;\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :foreach Update in=(\$JSON->\"result\") do={\r\ + \n :set UpdateID (\$Update->\"update_id\");\r\ + \n \$LogPrintVerbose debug \$ScriptName (\"Update \" . \$UpdateID . \":\ + \_\" . [ :serialize to=json \$Update ]);\r\ + \n\r\ + \n :local Message (\$Update->\"message\");\r\ + \n :local IsAnyReply ([ :typeof (\$Message->\"reply_to_message\") ] = \ + \"array\");\r\ + \n :local IsMyReply (\$TelegramMessageIDs->[ :tostr (\$Message->\"reply\ + _to_message\"->\"message_id\") ]);\r\ + \n :if ((\$IsMyReply = 1 || \$TelegramChatOffset->0 > 0 || \$Uptime > 5\ + m) && \$UpdateID >= \$TelegramChatOffset->2) do={\r\ + \n :local Trusted false;\r\ + \n :local Chat (\$Message->\"chat\");\r\ + \n :local From (\$Message->\"from\");\r\ + \n :local Command (\$Message->\"text\");\r\ + \n :local ThreadId [ \$IfThenElse (\$Message->\"is_topic_message\") (\ + \$Message->\"message_thread_id\") \"\" ];\r\ + \n\r\ + \n :foreach IdsTrusted in=(\$TelegramChatId, \$TelegramChatIdsTrusted\ + ) do={\r\ + \n :if (\$From->\"id\" = \$IdsTrusted || \\\r\ + \n \$From->\"username\" = \$IdsTrusted || \\\r\ + \n \$Chat->\"id\" = \$IdsTrusted) do={\r\ + \n :set Trusted true;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if (\$Trusted = true) do={\r\ + \n :local Done false;\r\ + \n :if (\$Command = \"\?\") do={\r\ + \n \$LogPrint info \$ScriptName (\"Sending notice for update \" .\ + \_\$UpdateID . \".\");\r\ + \n \$SendTelegram2 ({ origin=\$ScriptName; chatid=(\$Chat->\"id\"\ + ); silent=true; \\\r\ + \n replyto=(\$Message->\"message_id\"); threadid=\$ThreadId; \\\ + \r\ + \n subject=([ \$SymbolForNotification \"speech-balloon\" ] . \"\ + Telegram Chat\"); \\\r\ + \n message=([ \$IfThenElse ([ :len (\$From->\"first_name\") ] >\ + \_0) (\"Hello \" . (\$From->\"first_name\") . \"!\\n\\n\") ] . \\\r\ + \n \"Online\" . [ \$IfThenElse \$TelegramChatActive \" (and a\ + ctive!)\" ] . \", awaiting your commands!\") });\r\ + \n :set Done true;\r\ + \n }\r\ + \n :if (\$Done = false && [ :pick \$Command 0 1 ] = \"!\") do={\r\ + \n :if (\$Command ~ (\"^! *(\" . [ \$EscapeForRegEx \$Identity ] \ + . \"|@\" . \$TelegramChatGroups . \")\\\$\")) do={\r\ + \n :set TelegramChatActive true;\r\ + \n } else={\r\ + \n :set TelegramChatActive false;\r\ + \n }\r\ + \n \$LogPrint info \$ScriptName (\"Now \" . [ \$IfThenElse \$Tele\ + gramChatActive \"active\" \"passive\" ] . \\\r\ + \n \" from update \" . \$UpdateID . \"!\");\r\ + \n :set Done true;\r\ + \n }\r\ + \n :if (\$Done = false && (\$IsMyReply = 1 || (\$IsAnyReply = false\ + \_&& \\\r\ + \n \$TelegramChatActive = true)) && [ :len \$Command ] > 0) do\ + ={\r\ + \n :if ([ \$ValidateSyntax \$Command ] = true) do={\r\ + \n :local State \"\";\r\ + \n :local File (\"tmpfs/telegram-chat/\" . [ \$GetRandom20CharA\ + lNum 6 ]);\r\ + \n :if ([ \$MkDir \"tmpfs/telegram-chat\" ] = false) do={\r\ + \n \$LogPrint error \$ScriptName (\"Failed creating directory\ + !\");\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n \$LogPrint info \$ScriptName (\"Running command from update \ + \" . \$UpdateID . \": \" . \$Command);\r\ + \n :execute script=(\":do {\\n\" . \$Command . \"\\n} on-error=\ + { /file/add name=\\\"\" . \$File . \".failed\\\" };\" . \\\r\ + \n \"/file/add name=\\\"\" . \$File . \".done\\\"\") file=(\$\ + File . \"\\00\");\r\ + \n :if ([ \$WaitForFile (\$File . \".done\") [ \$EitherOr \$Tel\ + egramChatRunTime 20s ] ] = false) do={\r\ + \n :set State ([ \$SymbolForNotification \"warning-sign\" ] .\ + \_\"The command did not finish, still running in background.\\n\\n\");\r\ + \n }\r\ + \n :if ([ \$FileExists (\$File . \".failed\") ] = true) do={\r\ + \n :set State ([ \$SymbolForNotification \"cross-mark\" ] . \ + \"The command failed with an error!\\n\\n\");\r\ + \n }\r\ + \n :local Content ([ /file/read chunk-size=32768 file=\$File as\ + -value ]->\"data\");\r\ + \n \$SendTelegram2 ({ origin=\$ScriptName; chatid=(\$Chat->\"id\ + \"); silent=true; \\\r\ + \n replyto=(\$Message->\"message_id\"); threadid=\$ThreadId; \ + \\\r\ + \n subject=([ \$SymbolForNotification \"speech-balloon\" ] . \ + \"Telegram Chat\"); \\\r\ + \n message=([ \$SymbolForNotification \"gear\" ] . \"Command:\ + \\n\" . \$Command . \"\\n\\n\" . \\\r\ + \n \$State . [ \$IfThenElse ([ :len \$Content ] > 0) \\\r\ + \n ([ \$SymbolForNotification \"memo\" ] . \"Output:\\n\" .\ + \_\$Content) \\\r\ + \n ([ \$SymbolForNotification \"memo\" ] . \"No output.\") \ + ]) });\r\ + \n \$RmDir \"tmpfs/telegram-chat\";\r\ + \n } else={\r\ + \n \$LogPrint info \$ScriptName (\"The command from update \" .\ + \_\$UpdateID . \" failed syntax validation!\");\r\ + \n \$SendTelegram2 ({ origin=\$ScriptName; chatid=(\$Chat->\"id\ + \"); silent=false; \\\r\ + \n replyto=(\$Message->\"message_id\"); threadid=\$ThreadId; \ + \\\r\ + \n subject=([ \$SymbolForNotification \"speech-balloon\" ] . \ + \"Telegram Chat\"); \\\r\ + \n message=([ \$SymbolForNotification \"gear\" ] . \"Command:\ + \\n\" . \$Command . \"\\n\\n\" . \\\r\ + \n [ \$SymbolForNotification \"cross-mark\" ] . \"The comma\ + nd failed syntax validation!\") });\r\ + \n }\r\ + \n }\r\ + \n } else={\r\ + \n :local MessageText (\"Received a message from untrusted contact \ + \" . \\\r\ + \n [ \$IfThenElse ([ :len (\$From->\"username\") ] = 0) \"without\ + \_username\" (\"'\" . \$From->\"username\" . \"'\") ] . \\\r\ + \n \" (ID \" . \$From->\"id\" . \") in update \" . \$UpdateID . \ + \"!\");\r\ + \n :if (\$Command ~ (\"^! *\" . [ \$EscapeForRegEx \$Identity ] . \ + \"\\\$\")) do={\r\ + \n \$LogPrint warning \$ScriptName \$MessageText;\r\ + \n \$SendTelegram2 ({ origin=\$ScriptName; chatid=(\$Chat->\"id\"\ + ); silent=false; \\\r\ + \n replyto=(\$Message->\"message_id\"); threadid=\$ThreadId; \\\ + \r\ + \n subject=([ \$SymbolForNotification \"speech-balloon\" ] . \"\ + Telegram Chat\"); \\\r\ + \n message=(\"You are not trusted.\") });\r\ + \n } else={\r\ + \n \$LogPrint info \$ScriptName \$MessageText;\r\ + \n }\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint debug \$ScriptName (\"Already handled update \" . \$Upd\ + ateID . \".\");\r\ + \n }\r\ + \n }\r\ + \n :set TelegramChatOffset ([ :pick \$TelegramChatOffset 1 3 ], \\\r\ + \n [ \$IfThenElse (\$UpdateID >= \$TelegramChatOffset->2) (\$UpdateID +\ + \_1) (\$TelegramChatOffset->2) ]);\r\ + \n} do={\r\ + \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ + \n}\r\ + \n" +add comment="Script send Notifications in Telegram" dont-require-permissions=\ + no name=mod/AM-TG-Notifications owner=mod/AM-TG-Notifications policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: mod/AM-TG-Notifications\r\ + \n# Script comment: Script send Notifications in Telegram\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:global FlushTelegramQueue;\r\ + \n:global GetTelegramChatId;\r\ + \n:global NotificationFunctions;\r\ + \n:global PurgeTelegramQueue;\r\ + \n:global SendTelegram;\r\ + \n:global SendTelegram2;\r\ + \n# flush telegram queue\r\ + \n:set FlushTelegramQueue do={ :onerror Err {\r\ + \n :global TelegramQueue;\r\ + \n :global TelegramMessageIDs;\r\ + \n :global CertificateAvailable;\r\ + \n :global IsFullyConnected;\r\ + \n :global LogPrint;\r\ + \n :if ([ \$IsFullyConnected ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"System is not fully connected, not flushing.\ + \");\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$CertificateAvailable \"Go Daddy Root Certificate Authority - \ + G2\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\"\ + );\r\ + \n :return false;\r\ + \n }\r\ + \n :local AllDone true;\r\ + \n :local QueueLen [ :len \$TelegramQueue ];\r\ + \n :if ([ :len [ /system/scheduler/find where name=\"_FlushTelegramQueue\ + \" ] ] > 0 && \$QueueLen = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Flushing Telegram messages from scheduler,\ + \_but queue is empty.\");\r\ + \n }\r\ + \n :foreach Id,Message in=\$TelegramQueue do={\r\ + \n :if ([ :typeof \$Message ] = \"array\" ) do={\r\ + \n :onerror Err {\r\ + \n :local Data ([ /tool/fetch check-certificate=yes-without-crl out\ + put=user http-method=post \\\r\ + \n (\"https://api.telegram.org/bot\" . (\$Message->\"tokenid\") .\ + \_\"/sendMessage\") \\\r\ + \n http-data=(\$Message->\"http-data\") as-value ]->\"data\");\r\ + \n :set (\$TelegramQueue->\$Id);\r\ + \n :set (\$TelegramMessageIDs->[ :tostr ([ :deserialize from=json v\ + alue=\$Data ]->\"result\"->\"message_id\") ]) 1;\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Sending queued Telegram message failed: \ + \" . \$Err);\r\ + \n :set AllDone false;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :if (\$AllDone = true && \$QueueLen = [ :len \$TelegramQueue ]) do={\r\ + \n /system/scheduler/remove [ find where name=\"_FlushTelegramQueue\" ]\ + ;\r\ + \n :set TelegramQueue;\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n# get the chat id\r\ + \n:set GetTelegramChatId do={ :onerror Err {\r\ + \n :global TelegramTokenId;\r\ + \n :global CertificateAvailable;\r\ + \n :global LogPrint;\r\ + \n :if ([ \$CertificateAvailable \"Go Daddy Root Certificate Authority - \ + G2\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\"\ + );\r\ + \n :return false;\r\ + \n }\r\ + \n :local Data;\r\ + \n :onerror Err {\r\ + \n :set Data ([ /tool/fetch check-certificate=yes-without-crl output=us\ + er \\\r\ + \n (\"https://api.telegram.org/bot\" . \$TelegramTokenId . \"/getUpd\ + ates\?offset=0\" . \\\r\ + \n \"&allowed_updates=%5B%22message%22%5D\") as-value ]->\"data\");\ + \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Fetching data failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :local JSON [ :deserialize from=json value=\$Data ];\r\ + \n :local Count [ :len (\$JSON->\"result\") ];\r\ + \n :if (\$Count = 0) do={\r\ + \n \$LogPrint info \$0 (\"No message received.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local Message (\$JSON->\"result\"->(\$Count - 1)->\"message\");\r\ + \n \$LogPrint info \$0 (\"The chat id is: \" . (\$Message->\"chat\"->\"id\ + \"));\r\ + \n :if ((\$Message->\"is_topic_message\") = true) do={\r\ + \n \$LogPrint info \$0 (\"The thread id is: \" . (\$Message->\"message_\ + thread_id\"));\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n# send notification via telegram - expects one array argument\r\ + \n:set (\$NotificationFunctions->\"telegram\") do={\r\ + \n :local Notification \$1;\r\ + \n :global Identity;\r\ + \n :global IdentityExtra;\r\ + \n :global TelegramChatId;\r\ + \n :global TelegramChatIdOverride;\r\ + \n :global TelegramMessageIDs;\r\ + \n :global TelegramQueue;\r\ + \n :global TelegramThreadId;\r\ + \n :global TelegramThreadIdOverride;\r\ + \n :global TelegramTokenId;\r\ + \n :global TelegramTokenIdOverride;\r\ + \n :global CertificateAvailable;\r\ + \n :global CharacterReplace;\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ProtocolStrip;\r\ + \n :global SymbolForNotification;\r\ + \n :global UrlEncode;\r\ + \n :local EscapeMD do={\r\ + \n :local Text [ :tostr \$1 ];\r\ + \n :local Mode [ :tostr \$2 ];\r\ + \n :local Excl [ :tostr \$3 ];\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :local Chars {\r\ + \n \"body\"={ \"\\\\\"; \"`\" };\r\ + \n \"plain\"={ \"_\"; \"*\"; \"[\"; \"]\"; \"(\"; \")\"; \"~\"; \"`\"\ + ; \">\";\r\ + \n \"#\"; \"+\"; \"-\"; \"=\"; \"|\"; \"{\"; \"}\"; \".\"; \ + \"!\" };\r\ + \n }\r\ + \n :foreach Char in=(\$Chars->\$Mode) do={\r\ + \n :if ([ :typeof [ :find \$Excl \$Char ] ] = \"nil\") do={\r\ + \n :set Text [ \$CharacterReplace \$Text \$Char (\"\\\\\" . \$Char)\ + \_];\r\ + \n }\r\ + \n }\r\ + \n :if (\$Mode = \"body\") do={:return (\"```\\n\" . \$Text . \"\\n```\ + \")}\r\ + \n :return \$Text;\r\ + \n }\r\ + \n :local ChatId [ \$EitherOr (\$Notification->\"chatid\") \\\r\ + \n [ \$EitherOr (\$TelegramChatIdOverride->(\$Notification->\"origin\")\ + ) \$TelegramChatId ] ];\r\ + \n :local ThreadId [ \$EitherOr (\$Notification->\"threadid\") \\\r\ + \n [ \$EitherOr (\$TelegramThreadIdOverride->(\$Notification->\"origin\ + \")) \\\r\ + \n [ \$IfThenElse ([ :len (\$TelegramChatIdOverride->(\$Notification->\ + \"origin\")) ] = 0) \$TelegramThreadId ] ] ];\r\ + \n :local TokenId [ \$EitherOr (\$TelegramTokenIdOverride->(\$Notificatio\ + n->\"origin\")) \$TelegramTokenId ];\r\ + \n :if ([ :len \$TokenId ] = 0 || [ :len \$ChatId ] = 0) do={:return fals\ + e}\r\ + \n :if ([ :typeof \$TelegramMessageIDs ] = \"nothing\") do={:set Telegram\ + MessageIDs ({})}\r\ + \n :local Truncated false;\r\ + \n :local Text (\"*__\" . [ \$EscapeMD (\"[\" . \$IdentityExtra . \$Ident\ + ity . \"] \" . \\\r\ + \n (\$Notification->\"subject\")) \"plain\" ] . \"__*\\n\\n\");\r\ + \n :local LenSubject [ :len \$Text ];\r\ + \n :local LenMessage [ :len (\$Notification->\"message\") ];\r\ + \n :local LenLink ([ :len (\$Notification->\"link\") ] * 2);\r\ + \n :local LenSum (\$LenSubject + \$LenMessage + \$LenLink);\r\ + \n :if (\$LenSum > 3968) do={\r\ + \n :set Text (\$Text . [ \$EscapeMD ([ :pick (\$Notification->\"message\ + \") 0 (3840 - \$LenSubject - \$LenLink) ] . \"...\") \"body\" ]);\r\ + \n :set Truncated true;\r\ + \n } else={:set Text (\$Text . [ \$EscapeMD (\$Notification->\"message\")\ + \_\"body\" ])}\r\ + \n :if (\$LenLink > 0) do={\r\ + \n :set Text (\$Text . \"\\n\" . [ \$SymbolForNotification \"link\" ] .\ + \_\\\r\ + \n \"[\" . [ \$EscapeMD [ \$ProtocolStrip (\$Notification->\"link\") \ + ] \"plain\" ] . \"]\" . \\\r\ + \n \"(\" . [ \$EscapeMD (\$Notification->\"link\") \"plain\" ] . \")\ + \");\r\ + \n }\r\ + \n :if (\$Truncated = true) do={\r\ + \n :set Text (\$Text . \"\\n\" . [ \$SymbolForNotification \"scissors\"\ + \_] . \\\r\ + \n [ \$EscapeMD (\"The message was too long and has been truncated, c\ + ut off _\" . \\\r\ + \n ((\$LenSum - [ :len \$Text ]) * 100 / \$LenSum) . \"%_!\") \"plain\ + \" \"_\" ]);\r\ + \n }\r\ + \n :local HTTPData (\"chat_id=\" . \$ChatId . \"&disable_notification=\" \ + . (\$Notification->\"silent\") . \\\r\ + \n \"&reply_to_message_id=\" . (\$Notification->\"replyto\") . \"&mes\ + sage_thread_id=\" . \$ThreadId . \\\r\ + \n \"&disable_web_page_preview=true&parse_mode=MarkdownV2\");\r\ + \n :onerror Err {\r\ + \n :if ([ \$CertificateAvailable \"Go Daddy Root Certificate Authority \ + - G2\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\ + \");\r\ + \n :error false;\r\ + \n }\r\ + \n :local Data ([ /tool/fetch check-certificate=yes-without-crl output=\ + user http-method=post \\\r\ + \n (\"https://api.telegram.org/bot\" . \$TokenId . \"/sendMessage\") \ + \\\r\ + \n http-data=(\$HTTPData . \"&text=\" . [ \$UrlEncode \$Text ]) as-va\ + lue ]->\"data\");\r\ + \n :set (\$TelegramMessageIDs->[ :tostr ([ :deserialize from=json value\ + =\$Data ]->\"result\"->\"message_id\") ]) 1;\r\ + \n } do={\r\ + \n \$LogPrint info \$0 (\"Failed sending Telegram notification: \" . \$\ + Err . \" - Queuing...\");\r\ + \n :if ([ :typeof \$TelegramQueue ] = \"nothing\") do={:set TelegramQue\ + ue ({})}\r\ + \n :set Text (\$Text . \"\\n\" . [ \$SymbolForNotification \"alarm-cloc\ + k\" ] . \\\r\ + \n [ \$EscapeMD (\"This message was queued since _\" . [ /system/cloc\ + k/get date ] . \\\r\ + \n \" \" . [ /system/clock/get time ] . \"_ and may be obsolete.\") \ + \"plain\" \"_\" ]);\r\ + \n :set (\$TelegramQueue->[ :len \$TelegramQueue ]) { tokenid=\$TokenId\ + ;\r\ + \n http-data=(\$HTTPData . \"&text=\" . [ \$UrlEncode \$Text ]) };\r\ + \n :if ([ :len [ /system/scheduler/find where name=\"_FlushTelegramQueu\ + e\" ] ] = 0) do={\r\ + \n /system/scheduler/add name=\"_FlushTelegramQueue\" interval=1m sta\ + rt-time=startup \\\r\ + \n on-event=(\":global FlushTelegramQueue; \\\$FlushTelegramQueue;\ + \");\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n# purge the Telegram queue\r\ + \n:set PurgeTelegramQueue do={\r\ + \n :global TelegramQueue;\r\ + \n /system/scheduler/remove [ find where name=\"_FlushTelegramQueue\" ];\ + \r\ + \n :set TelegramQueue;\r\ + \n}\r\ + \n# send notification via telegram - expects at least two string arguments\ + \r\ + \n:set SendTelegram do={ :onerror Err {\r\ + \n :global SendTelegram2;\r\ + \n \$SendTelegram2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3; sil\ + ent=\$4 });\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n# send notification via telegram - expects one array argument\r\ + \n:set SendTelegram2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n (\$NotificationFunctions->\"telegram\") (\"\\\$NotificationFunctions->\ + \\\"telegram\\\"\") \$Notification;\r\ + \n}\r\ + \n" +add dont-require-permissions=no name=testIfThenElseAndEitherOr owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source=":local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:local ExitError;\r\ + \n#:local IfThenElse;\r\ + \n#:local EitherOr;\r\ + \n\r\ + \n:local one 11;\r\ + \n:local two 8;\r\ + \n#:log warning ([ \$IfThenElse (\$one != 0) \$one \$two ]);\r\ + \n:local Test; # [ :totime \"22s\" ];\r\ + \n\r\ + \n:local IfThenElse do={:if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] \ + = true) do={:return \$2}; :return \$3;}\r\ + \n:local EitherOr do={\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:if ((\$1 != 0) = true) do={:retur\ + n \$1} else={:return \$2};}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:if ((\$1 > 0s) = true) do={:retu\ + rn \$1} else={:return \$2};}\r\ + \n :if ([ :len [ :tostr \$1 ] ] > 0) do={:return \$1} else={:return \$2};\ + \r\ + \n}\r\ + \n\r\ + \n:log warning ([ \$IfThenElse (\$one != 0) \$one \$two ]);\r\ + \n\r\ + \n:set Test [ \$EitherOr \$Test \"\" ];\r\ + \n:log warning (\"\\\$ Test = \" . \$Test);\r\ + \n\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :local IfThenElse;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n :log error (\$Name [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\$\") \ + \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n\r\ + \n#:log warning ([ \$IfThenElse (\$one != 0) \$one \$two ]);\r\ + \n\r\ + \n:set ExitOK true;\r\ + \n\$ExitError \$ExitOK \$ScriptName \"Err test custom\";" +add comment="Update and Backup send notification to EMail" \ + dont-require-permissions=no name=AM-Backup-UpdateEmail owner=\ + AM-Backup-UpdateEmail policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-Backup-UpdateEmail\r\ + \n# Script comment: Update and Backup send notification to EMail\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version>=6.43.7\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Updated: 15/04/2025\r\ + \n# Website: https://github.com/beeyev\r\ + \n# Notification e-mail (Make sure you have configured Email settings in T\ + ools -> Email)\r\ + \n:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ + delay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n:local IfThenElse do={:if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] \ + = true) do={:return \$2}; :return \$3;}\r\ + \n:local EitherOr do={\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:if ((\$1 != 0) = true) do={:retur\ + n \$1} else={:return \$2};}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:if ((\$1 > 0s) = true) do={:retu\ + rn \$1} else={:return \$2};}\r\ + \n :if ([ :len [ :tostr \$1 ] ] > 0) do={:return \$1} else={:return \$2};\ + \r\ + \n}\r\ + \n:local ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :if (\$ExitOK = \"false\") do={:log error (\$Name [ \$IfThenElse ([ :p\ + ick \$Name 0 1 ] = \"\\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);}\r\ + \n}\r\ + \n\r\ + \n:global LogPrint;\r\ + \n:global EditSchedulers;\r\ + \n:global DevInfoIncludeIP;\r\ + \n\r\ + \n:local SchedInterval \"7d\";\r\ + \n:local SchedStartTime \"03:41:27\";\r\ + \n:local SchedComment \"Every 7 Day Check For Update and Backup send notif\ + ication to EMail.\";\r\ + \n\r\ + \n# Function to add or edit schedulers for scripts, to ensure they are set\ + \_up correctly\r\ + \n# How to use:\r\ + \n# Call this function with the following parameters:\r\ + \n# 1. \$1 - Scheduler name (usually same as script name) [*]\r\ + \n# 2. \$2 - Interval (e.g. \"1d\" (default is \"1d\")) [**]\r\ + \n# 3. \$3 - Start Time (e.g. \"00:00:00\", default is current time) [**]\ + \r\ + \n# 4. \$4 - Comment (optional, default: \"Scheduler for script: \")\ + \_[**]\r\ + \n# 5. \$5 - On Event command (e.g. \"/system/script { run ; }\" (de\ + fault is \"/system/script { run \$SchedName; }\")) [**]\r\ + \n# 6. \$6 - Policy (e.g. \"ftp,reboot,read,write,policy,test,password,sni\ + ff,sensitive,romon\" (default is the same)) [**]\r\ + \n# 7. \$7 - Start Date (e.g. \"jan/01/1970\", default is current date) [*\ + *]\r\ + \n# Notes:\r\ + \n# * - Scheduler name is required, and is used to identify the scheduler\ + \_to create or edit. It is usually the same as the script name (\$ScriptNa\ + me).\r\ + \n# ** - If optional parameters are not provided, default values will be u\ + sed.\r\ + \n# This allows for quick setup with minimal parameters, while still \ + providing flexibility for customization.\r\ + \n# Example usage:\r\ + \n# :if ([ \$EditSchedulers \"my-script\" ] = false) do={:set ExitOK false\ + ; :error true;}\r\ + \n# :if ([ \$EditSchedulers \"my-script\" \"1d\" \"03:41:27\" \"My custom \ + scheduler comment\" false false \"jan/01/1970\" ] = false) do={:set ExitOK\ + \_false; :error true;}\r\ + \n\r\ + \n:set EditSchedulers do={\r\ + \n :local SchedName [ :tostr \$1 ];\r\ + \n :if ([ :len \$SchedName ] = 0) do={ :return false; }\r\ + \n :local Interval [ :tostr \$2 ];\r\ + \n :if ([ :len \$Interval ] = 0) do={ :set Interval \"1d\"; }\r\ + \n :local StartTime [ :tostr \$3 ];\r\ + \n :if ([ :len \$StartTime ] = 0) do={ :set StartTime [/system/clock/get \ + time]; }\r\ + \n :local Comment [ :tostr \$4 ];\r\ + \n :if ([ :len \$Comment ] = 0) do={ :set Comment \"Scheduler for script:\ + \_\$SchedName\"; }\r\ + \n :local OnEvent [ :tostr \$5 ];\r\ + \n :if ([ :len \$OnEvent ] = 0) do={ :set OnEvent \"/system/script { run \ + \$SchedName; }\"; }\r\ + \n :local Policy [ :tostr \$6 ];\r\ + \n :if ([ :len \$Policy ] = 0) do={ :set Policy \"ftp,reboot,read,write,p\ + olicy,test,password,sniff,sensitive,romon\"; }\r\ + \n :local StartDate [ :tostr \$7 ];\r\ + \n :if ([ :len \$StartDate ] = 0) do={ :set StartDate [/system/clock/get \ + date]; }\r\ + \n\r\ + \n :onerror Err {\r\ + \n # Check if scheduler exists, if not - create it\r\ + \n :if ([ :len [ /system/scheduler/find where name=\$SchedName ] ] = 0)\ + \_do={\r\ + \n :log warning (\$SchedName . \"System Scheduler for script: \" . \$\ + SchedName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add comment=\$Comment interval=\$Interval name=\ + \$SchedName on-event=\$OnEvent policy=\$Policy start-date=\$StartDate star\ + t-time=\$StartTime;\r\ + \n }\r\ + \n # Check if scheduler parameters are correct, if not - fix them\r\ + \n :if ([ /system/scheduler/get \$SchedName comment ] != \$Comment) do=\ + {\r\ + \n /system/scheduler/set \$SchedName comment=\$Comment;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName interval ] != \$Interval) d\ + o={\r\ + \n /system/scheduler/set \$SchedName interval=\$Interval;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName on-event ] != \$OnEvent) do\ + ={\r\ + \n /system/scheduler/set \$SchedName on-event=\$OnEvent;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName policy ] != \$Policy) do={\ + \r\ + \n /system/scheduler/set \$SchedName policy=\$Policy;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName start-date ] != \$StartDate\ + ) do={\r\ + \n /system/scheduler/set \$SchedName start-date=\$StartDate;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \$SchedName start-time ] != \$StartTime\ + ) do={\r\ + \n /system/scheduler/set \$SchedName start-time=\$StartTime;\r\ + \n }\r\ + \n } do={:log error (\$SchedName . \"Failed to add/modify scheduler for '\ + \" . \$SchedName . \"' failed: \" . \$Err); :return false};\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:if ([ \$EditSchedulers \$ScriptName \$SchedInterval \$SchedStartTime \$\ + SchedComment ] = false) do={\r\ + \n :log error (\$ScriptName . \"Failed to add/modify scheduler for \" . \ + \$ScriptName . \"!\");\r\ + \n :set ExitOK true;\r\ + \n :error true;\r\ + \n}\r\ + \n\r\ + \n# Local Function CheckOSUpdateMode\r\ + \n:local CheckOSUpdateMode;\r\ + \n:set CheckOSUpdateMode do={\r\ + \n :local NewMode [ :tostr \$1 ];\r\ + \n :if ([ :len \$NewMode ] = 0) do={\r\ + \n :log error (\$0 . \"/nFunction /\$CheckOSUpdateMode received empty v\ + alue!\");\r\ + \n :return false;\r\ + \n :error true;\r\ + \n }\r\ + \n\r\ + \n :global BackupAndUpdateMode;\r\ + \n :global OldMode [ :tostr \$BackupAndUpdateMode ];\r\ + \n :if (\$NewMode != \$BackupAndUpdateMode && \$NewMode = \"updateOnce\")\ + \_do={\r\ + \n :set BackupAndUpdateMode [ :tostr \$NewMode ];\r\ + \n :log info (\$0 . \"/nOk. /\$BackupAndUpdateMode set to: '\" . \$NewM\ + ode . \"'.\\nYou're a good boy! ))\\nI'm launching the update in 5 seconds\ + .\");\r\ + \n :delay 5;\r\ + \n /system/script { run \$ScriptName; };\r\ + \n } else={\r\ + \n :log warning (\$0 . \"/nFunction /\$CheckOSUpdateMode received value: \ + '\" . \$NewMode . \"', but is may be only \\\"updateOnce\\\"!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n :error false;\r\ + \n}\r\ + \n\r\ + \n# :if ([ :len [ /system/scheduler/find where name=\"running-from-backup\ + -partition\" ] ] > 0) do={\r\ + \n# \$LogPrint warning \$ScriptName (\"Running from backup partition, r\ + efusing to act.\");\r\ + \n# :set ExitOK true;\r\ + \n# :error false;\r\ + \n# }\r\ + \n\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n:global forceBackup;\r\ + \n:global BackupPassword;\r\ + \n:global BackupSens;\r\ + \n:global updateChannel;\r\ + \n\r\ + \n:global DevInfoIncludeIP;\r\ + \n\r\ + \n# Installs patch updates only (BackupAndUpdateMode = \"osupdate\").\r\ + \n# Works for `stable` and `long-term` channels.\r\ + \n# Updates only if MAJOR.MINOR match (e.g. 6.43.2 > 6.43.6 allowed, 6.44.\ + 1 skipped).\r\ + \n# Sends info if a newer (non-patch) version is found.\r\ + \n:local installOnlyPatchUpdates false;\r\ + \n:local scriptVersion \"26.04.30\";\r\ + \n:local copyrightUrl \"https://www.github.com/vados-dev/\";\r\ + \n#Script messages prefix\r\ + \n:local SMP \"BkpAndUpdate:\";\r\ + \n\r\ + \n:local exitErrorMessage \"\$SMP script stopped due to an error. Please c\ + heck logs for more details.\";\r\ + \n:log info \"\\n\\n\$SMP Script \\\"Mikrotik RouterOS automatic backup & \ + update\\\" v.\$scriptVersion started.\";\r\ + \n:log info \"\$SMP Script Mode: `\$BackupAndUpdateMode`, Update channel: \ + `\$updateChannel`, Force backup: `\$forceBackup`, Install only patch updat\ + es: `\$installOnlyPatchUpdates`\";\r\ + \n\r\ + \n## vv FUNCTIONS vv ##\r\ + \n:global WaitCheckUpdates; \$WaitCheckUpdates;\r\ + \n:global MiniDateTimeStamp;\r\ + \n:local MDTSFix [\$MiniDateTimeStamp];\r\ + \n:global Identity;\r\ + \n:global IdentityShort;\r\ + \n:global devBoardName;\r\ + \n:global runningVersion;\r\ + \n:global runningChannel;\r\ + \n:global devModel;\r\ + \n:global devRbSerialNumber;\r\ + \n:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n\r\ + \n# Checks if two RouterOS version strings differ only by the patch versio\ + n\r\ + \n# :put [\$FuncIsPatchUpdateOnly \"6.2.1\" \"6.2.4\"] # Output: true\r\ + \n# :put [\$FuncIsPatchUpdateOnly \"6.2.1\" \"6.3.1\"] # Output: false\r\ + \n:local FuncIsPatchUpdateOnly do={\r\ + \n :local ver1 \$1;\r\ + \n :local ver2 \$2;\r\ + \n # Extract the major and minor components from a version\r\ + \n :local extractMajorMinor do={\r\ + \n :local ver \$1;\r\ + \n :local dot1 [:find \$ver \".\"];\r\ + \n :if (\$dot1 = -1) do={:return \$ver}\r\ + \n :local major [:pick \$ver 0 \$dot1];\r\ + \n :local rest [:pick \$ver (\$dot1 + 1) [:len \$ver]];\r\ + \n :local dot2 [:find \$rest \".\"];\r\ + \n :local minor \$rest;\r\ + \n :if (\$dot2 >= 0) do={:set minor [:pick \$rest 0 \$dot2]}\r\ + \n :return (\$major . \".\" . \$minor);\r\ + \n }\r\ + \n\r\ + \n# Compare the major and minor components of both version strings\r\ + \n:if ([\$extractMajorMinor \$ver1] = [\$extractMajorMinor \$ver2]) do={:r\ + eturn true}\r\ + \n :return false;\r\ + \n}\r\ + \n# Creates backups and returns array of names\r\ + \n# Possible arguments:\r\ + \n# \$1 - file name, without extension\r\ + \n# \$2 - password (optional)\r\ + \n# \$3 - sensitive data in config (optional, default: false)\r\ + \n# Example:\r\ + \n#:put [\$FuncCreateBackups \$backupName]\r\ + \n:local FuncCreateBackups do={\r\ + \n :local backupName [ :tostr \$1 ];\r\ + \n :local BackPass \$2;\r\ + \n :local BackSens \$3;\r\ + \n\r\ + \n #Script messages prefix\r\ + \n :local SMP \"BkpAndUpdate:\";\r\ + \n :local exitErrorMessage \"\$SMP script stopped due to an error. Please\ + \_check logs for more details.\";\r\ + \n :log info (\"\$SMP global function `FuncCreateBackups` started, input:\ + \_`\$backupName`\");\r\ + \n\r\ + \n # validate required parameter: backupName\r\ + \n :if ([:typeof \$backupName] != \"str\" or [:len \$backupName] = 0) do=\ + {\r\ + \n :log error \"\$SMP parameter 'backupName' is required and must be a \ + non-empty string\";\r\ + \n# :log warning \"\$SMP parameter '\\\$backupName' is required and mus\ + t be a non-empty string.\\nI set '\\\$backupName' to 'default-backup'\";\r\ + \n# :set \$backupName \"default-backup\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n\r\ + \n :local backupFileSys \"\$backupName.backup\";\r\ + \n :local backupFileConfig \"\$backupName.rsc\";\r\ + \n :local backupNames {\$backupFileSys;\$backupFileConfig};\r\ + \n\r\ + \n ## Perform system backup\r\ + \n :if ([:len \$BackPass] = 0) do={\r\ + \n :log info (\"\$SMP starting backup without password, backup name: `\ + \$backupName`\");\r\ + \n /system backup save dont-encrypt=yes name=\$backupName;\r\ + \n } else={\r\ + \n :log info (\"\$SMP starting backup with password, backup name: `\$ba\ + ckupName`\");\r\ + \n /system backup save password=\$BackPass name=\$backupName;\r\ + \n }\r\ + \n :log info (\"\$SMP system backup created: `\$backupFileSys`\");\r\ + \n ## Export config file\r\ + \n :if (\$BackSens = true) do={\r\ + \n :log info (\"\$SMP starting export config with sensitive data, backu\ + p name: `\$backupName`\");\r\ + \n # Since RouterOS v7 it needs to be explicitly set that we want to ex\ + port sensitive data\r\ + \n :if ([:pick [/system resource get version] 0 1] < 7) do={\r\ + \n :execute \"/export compact terse file=\$backupName\";\r\ + \n } else={\r\ + \n :execute \"/export compact show-sensitive terse file=\$backupName\ + \";\r\ + \n }\r\ + \n } else={\r\ + \n :log info (\"\$SMP starting export config without sensitive data, ba\ + ckup name: `\$backupName`\");\r\ + \n /export compact hide-sensitive terse file=\$backupName;\r\ + \n }\r\ + \n :log info (\"\$SMP Config export complete: `\$backupFileConfig`\");\r\ + \n :log info (\"\$SMP Waiting a little to ensure backup files are written\ + \");\r\ + \n :delay 20;\r\ + \n :if ([:len [/file find name=\$backupFileSys]] > 0) do={\r\ + \n :log info (\"\$SMP system backup file successfully saved to the file\ + \_system: `\$backupFileSys`\");\r\ + \n } else={\r\ + \n :log error (\"\$SMP system backup was not created, file does not exi\ + st: `\$backupFileSys`\");\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n :if ([:len [/file find name=\$backupFileConfig]] > 0) do={\r\ + \n :log info (\"\$SMP config backup file successfully saved to the file\ + \_system: `\$backupFileConfig`\");\r\ + \n } else={\r\ + \n :log error (\"\$SMP config backup was not created, file does not exi\ + st: `\$backupFileConfig`\");\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n :log info (\"\$SMP global function `FuncCreateBackups` finished. Creat\ + ed backups, system: `\$backupFileSys`, config: `\$backupFileConfig`\")\r\ + \n :return \$backupNames;\r\ + \n}\r\ + \n# Sends an email\r\ + \n# Parameters:\r\ + \n# \$1 - to (email address)\r\ + \n# \$2 - subject\r\ + \n# \$3 - body\r\ + \n# \$4 - file attachments (optional; pass \"\" if not needed)\r\ + \n#\r\ + \n# Example:\r\ + \n# \$FuncSendEmailSafe \"admin@domain.com\" \"Backup Done\" \"Backup comp\ + lete.\" \"backup1.backup\"\r\ + \n:local FuncSendEmailSafe do={\r\ + \n :global EmailGeneralTo;\r\ + \n :local emailSubject \$2;\r\ + \n :local emailBody \$3;\r\ + \n :local emailAttachments \$4;\r\ + \n :local SMP \"Bkp&Upd:\";\r\ + \n :local exitErrorMessage \"\$SMP script stopped due to an error. Please\ + \_check logs for more details.\";\r\ + \n :log info \"\$SMP Attempting to send email to `\$EmailGeneralTo`\";\r\ + \n # SAFETY: wait for any previously queued email to finish\r\ + \n :local waitTimeoutPre 60;\r\ + \n :local waitCounterPre 0;\r\ + \n :while (([/tool e-mail get last-status] = \"resolving-dns\" or [/tool \ + e-mail get last-status] = \"in-progress\")) do={\r\ + \n :if (\$waitCounterPre >= \$waitTimeoutPre) do={\r\ + \n :log error \"\$SMP Email send aborted: previous send did not compl\ + ete after \$waitTimeoutPre seconds\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n :log info \"\$SMP Waiting for previous email to finish (status: \$[/\ + tool e-mail get last-status])...\";\r\ + \n :delay 1; \r\ + \n :set waitCounterPre (\$waitCounterPre + 1);\r\ + \n }\r\ + \n # Send the email\r\ + \n :do {\r\ + \n /tool e-mail send to=\$EmailGeneralTo subject=\$emailSubject body=\$\ + emailBody file=\$emailAttachments;\r\ + \n } on-error={\r\ + \n :log error \"\$SMP Email send command failed to execute. Check logs \ + and verify email settings.\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n # Wait for send status to change from \"in-progress\" / \"resolving-dn\ + s\"\r\ + \n :local waitTimeout 60;\r\ + \n :local waitCounter 0;\r\ + \n :local emailStatus \"\";\r\ + \n :log info \"\$SMP Waiting for email to be sent, timeout in `\$waitTime\ + out` seconds...\";\r\ + \n :while (\$waitCounter < \$waitTimeout) do={\r\ + \n :set emailStatus [/tool e-mail get last-status];\r\ + \n :if (\$emailStatus != \"in-progress\" and \$emailStatus != \"resolvi\ + ng-dns\") do={\r\ + \n :log info \"\$SMP Email send status received: \$emailStatus\";\r\ + \n # exit loop\r\ + \n :set waitCounter \$waitTimeout;\r\ + \n } else={:delay 1; :set waitCounter (\$waitCounter + 1)}\r\ + \n }\r\ + \n # Final decision based on last status\r\ + \n :if (\$emailStatus = \"succeeded\") do={\r\ + \n :log info \"\$SMP Email successfully sent to `\$EmailGeneralTo`\";\ + \r\ + \n } else={\r\ + \n :log error \"\$SMP Email failed to send. Status: `\$emailStatus`. Ch\ + eck logs for more details and verify email settings.\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n}\r\ + \n# Global variable to track current update step\r\ + \n# They need to be initialized here first to be available in the script\r\ + \n:global buGlobalVarTargetOsVersion;\r\ + \n:global buGlobalVarScriptStep;\r\ + \n:local scriptStep \$buGlobalVarScriptStep;\r\ + \n:do {\r\ + \n /system/script/environment remove buGlobalVarScriptStep;\r\ + \n} on-error={}\r\ + \n:if ([:len \$scriptStep] = 0) do={\r\ + \n :set scriptStep 1;\r\ + \n}\r\ + \n## ^^ FUNCTIONS ^^ ##\r\ + \n#\r\ + \n# Initial validation\r\ + \n## Check email settings\r\ + \n:if ([:len \$EmailGeneralTo] < 3) do={\r\ + \n :log error (\"\$SMP Parameter `\\\$EmailGeneralTo` is not set, or cont\ + ains invalid value. Script stopped.\");\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n# Values will be defined later in the script\r\ + \n:local emailServer \"\";\r\ + \n:local emailFromAddress [/tool e-mail get from];\r\ + \n:log info \"\$SMP Validating email settings...\";\r\ + \n:do {\r\ + \n :set emailServer [/tool e-mail get server];\r\ + \n} on-error={\r\ + \n # This is a workaround for the RouterOS v7.12 and older versions\r\ + \n :set emailServer [/tool e-mail get address];\r\ + \n}\r\ + \n:if (\$emailServer = \"0.0.0.0\") do={\r\ + \n :log error (\"\$SMP Email server address is not correct: `\$emailServe\ + r`, check `Tools -> Email`. Script stopped.\");\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n:if ([:len \$emailFromAddress] < 3) do={\r\ + \n :log error (\"\$SMP Email configuration FROM address is not correct: `\ + \$emailFromAddress`, check `Tools -> Email`. Script stopped.\");\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n# Script mode validation\r\ + \n:if (\$BackupAndUpdateMode != \"backup\" and \$BackupAndUpdateMode != \"\ + osupdate\" and \$BackupAndUpdateMode != \"updateOnce\" and \$BackupAndUpda\ + teMode != \"osnotify\") do={\r\ + \n :log error (\"\$SMP Script parameter `\\\$BackupAndUpdateMode` is not \ + set, or contains invalid value: `\$BackupAndUpdateMode`. Script stopped.\"\ + );\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n# Update channel validation\r\ + \n:if (\$updateChannel != \"stable\" and \$updateChannel != \"long-term\" \ + and \$updateChannel != \"testing\" and \$updateChannel != \"development\")\ + \_do={\r\ + \n :log error (\"\$SMP Script parameter `\\\$updateChannel` is not set, o\ + r contains invalid value: `\$updateChannel`. Script stopped.\");\r\ + \n :error \$exitErrorMessage;\r\ + \n}\r\ + \n# Verify if script is set to install patch updates and if the update cha\ + nnel is valid\r\ + \n:if ((\$BackupAndUpdateMode = \"osupdate\" or \$BackupAndUpdateMode = \"\ + updateOnce\") and \$installOnlyPatchUpdates = true) do={\r\ + \n :if (\$updateChannel != \"stable\" and \$updateChannel != \"long-term\ + \") do={\r\ + \n :log error (\"\$SMP Patch-only updates enabled, but update channel `\ + \$updateChannel` is invalid. Only `stable` and `long-term` are supported. \ + Script stopped\");\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n \r\ + \n :if (\$runningChannel != \"stable\" and \$runningChannel != \"long-ter\ + m\") do={\r\ + \n :log error (\"\$SMP Script is set to install only patch updates, but\ + \_the installed RouterOS version is not from `stable` or `long-term` chann\ + el: `\$runningChannel`. Script stopped\");\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n}\r\ + \n#\r\ + \n\r\ + \n:local rawTime [/system clock get time];\r\ + \n:local rawDate [/system clock get date];\r\ + \n\r\ + \n:local deviceOsVerAndChannelRunning [/system/resource/get version];\r\ + \n\r\ + \n:local backupNameTemplate (\"backup_v\" . \$runningVersion . \"_\" .\ + \_\$runningChannel . \"_\" . \$MDTSFix);\r\ + \n:local backupNameBeforeUpdate (\$backupNameTemplate . \"_before_update\"\ + );\r\ + \n:local backupNameAfterUpdate (\$backupNameTemplate . \"_after_update\")\ + ;\r\ + \n\r\ + \n## Email body template\r\ + \n:local mailSubjectPrefix \"\$SMP Device - `\$IdentityShort`\";\r\ + \n:local mailBodyCopyright \"Mikrotik RouterOS automatic backup & update \ + (ver. \$scriptVersion) \\n\$copyrightUrl\";\r\ + \n:local changelogUrl \"Check RouterOS changelog: https://mikrotik.com\ + /download/changelogs/\";\r\ + \n:local mailBodyDeviceInfo \"\";\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"Device information:\")\ + ;\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\n-------------------\ + --\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nName: \$Identity\")\ + ;\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nModel: \$devModel\"\ + );\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nBoard: \$devBoardNa\ + me\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nSerial number: \$de\ + vRbSerialNumber\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nRouterOS version: v\ + \$deviceOsVerAndChannelRunning\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nBuild time: \$[/sys\ + tem/resource/get build-time]\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nRouterboard FW Avai\ + lable: \$ROsVerAvail\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nDevice date-time: \ + \$rawDate \$rawTime (\$[/system/clock/get time-zone-name ])\");\r\ + \n:set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nUptime: \$[/system/\ + resource/get uptime]\");\r\ + \n## IP address detection\r\ + \n:if ([ \$DevInfoIncludeIP ] = true) do={\r\ + \n :global GetPubIp;\r\ + \n :local PublicIpAddress [ \$GetPubIp ];\r\ + \n :set mailBodyDeviceInfo (\$mailBodyDeviceInfo . \"\\nPublic IP address\ + : \" . \$PublicIpAddress . \".\");\r\ + \n :log info \"\$SMP Public IP address detected: \$PublicIpAddress\";\r\ + \n} \r\ + \n\r\ + \n:local mailAttachments [:toarray \"\"];\r\ + \n:if (\$scriptStep = 1 or \$scriptStep = 3) do={\r\ + \n :if (\$scriptStep = 3) do={\r\ + \n :log info (\"\$SMP Waiting for one minute before continuing to the f\ + inal step.\");\r\ + \n :delay 1m;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n## STEP 1: Create backups, check for new RouterOS, and send email\r\ + \n## Steps 2\C3\A23 run only if auto-update is enabled and a new version i\ + s available\r\ + \n:if (\$scriptStep = 1) do={\r\ + \n :global BackupPassword;\r\ + \n :global BackupSens;\r\ + \n :local isNewOsUpdateAvailable false;\r\ + \n :local isLatestOsAlreadyInstalled true;\r\ + \n :local isOsNeedsToBeUpdated false;\r\ + \n :local isUpdateCheckSucceeded false;\r\ + \n :local isEmailNeedsToBeSent false;\r\ + \n :local mailSubjectPartAction \"\";\r\ + \n :local mailPtBodyAction \"\";\r\ + \n :local mailPtSubjectBackup \"\";\r\ + \n :local mailPtBodyBackup \"\";\r\ + \n # Checking for new version\r\ + \n :if (\$BackupAndUpdateMode = \"osupdate\" or \$BackupAndUpdateMode = \ + \"osnotify\" or \$BackupAndUpdateMode = \"updateOnce\") do={\r\ + \n :log info (\"\$SMP Setting update channel to `\$updateChannel`\");\r\ + \n /system/package/update/set channel=\$updateChannel;\r\ + \n :log info (\"\$SMP Checking for new RouterOS version. Current instal\ + led version is: `\$runningVersion`\");\r\ + \n \$LogPrint debug \$ScriptName (\"Checking for updates...\");\r\ + \n \r\ + \n# /system/package/update/check-for-updates without-paging as-value;\ + \r\ + \n# /system/package/update check-for-updates;\r\ + \n :delay 5s;\r\ + \n :set PkgUpdStatus [ /system/package/update/get status ];\r\ + \n :if (\$PkgUpdStatus = \"New version is available\") do={\r\ + \n :set ROsVerAvail [/system/package/update/get latest-version];\r\ + \n }\r\ + \n\r\ + \n :if (\$PkgUpdStatus = \"New version is available\") do={\r\ + \n :log info (\"\$SMP New RouterOS version is available: `\$ROsVerAva\ + il`\");\r\ + \n :set isNewOsUpdateAvailable true;\r\ + \n :set isLatestOsAlreadyInstalled false;\r\ + \n :set isUpdateCheckSucceeded true;\r\ + \n :set isEmailNeedsToBeSent true;\r\ + \n :set mailSubjectPartAction \"New RouterOS available\";\r\ + \n :set mailPtBodyAction \"New RouterOS version is available, curren\ + t version: v\$runningVersion, new version: v\$ROsVerAvail. \\n\$changelogU\ + rl\";\r\ + \n } else={\r\ + \n :if (\$PkgUpdStatus = \"System is already up to date\") do={\r\ + \n :log info (\"\$SMP No new RouterOS version is available, the lat\ + est version is already installed: `v\$runningVersion`\");\r\ + \n :set isUpdateCheckSucceeded true;\r\ + \n :set mailSubjectPartAction \"No os update available\";\r\ + \n :set mailPtBodyAction \"No new RouterOS version is available, t\ + he latest version is already installed: `v\$runningVersion`\";\r\ + \n } else={\r\ + \n :log error (\"\$SMP Failed to check for new RouterOS version. Pa\ + ckage check status: `\$PkgUpdStatus`\");\r\ + \n :set isEmailNeedsToBeSent true;\r\ + \n :set mailSubjectPartAction \"Error unable to check new os versio\ + n\";\r\ + \n :set mailPtBodyAction \"An error occurred while checking for a \ + new RouterOS version.\\nStatus returned: `\$PkgUpdStatus`\\n\\nPlease revi\ + ew the logs on the device for more details and verify internet connectivit\ + y.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n # Checking if the script needs to install new os version\r\ + \n :if ((\$BackupAndUpdateMode = \"osupdate\" or \$BackupAndUpdateMode = \ + \"updateOnce\") and \$isNewOsUpdateAvailable = true) do={\r\ + \n :if (\$installOnlyPatchUpdates = true) do={\r\ + \n :if ([\$FuncIsPatchUpdateOnly \$runningVersion \$ROsVerAvail] = tr\ + ue) do={\r\ + \n :log info \"\$SMP New RouterOS version is available, and it is a\ + \_patch update. Current version: v\$runningVersion, new version: v\$ROsVer\ + Avail\";\r\ + \n :set isOsNeedsToBeUpdated true;\r\ + \n } else={\r\ + \n :log info \"\$SMP The script will not install this update, becau\ + se it is not a patch update. Current version: v\$runningVersion, new versi\ + on: v\$ROsVerAvail\";\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nThis update wil\ + l not be installed, because the script is set to install only patch update\ + s.\");\r\ + \n }\r\ + \n } else={\r\ + \n :set isOsNeedsToBeUpdated true;\r\ + \n }\r\ + \n }\r\ + \n # Checking If the script needs to create a backup\r\ + \n :if (\$forceBackup = true or \$BackupAndUpdateMode = \"backup\" or \$i\ + sOsNeedsToBeUpdated = true) do={\r\ + \n :log info (\"\$SMP Starting backup process.\");\r\ + \n :set isEmailNeedsToBeSent true;\r\ + \n :local backupName \$backupNameTemplate;\r\ + \n # This means it's the first step where we create a backup before the\ + \_update process\r\ + \n :if (\$isOsNeedsToBeUpdated = true) do={\r\ + \n :set backupName \$backupNameBeforeUpdate;\r\ + \n #Email body if the purpose of the script is to update the device\r\ + \n :set mailSubjectPartAction \"Update preparation\";\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nThe update proces\ + s for device '\$Identity' is scheduled to upgrade RouterOS from version v.\ + \$runningVersion to version v.\$ROsVerAvail (Update channel: \$updateChann\ + el)\");\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nPlease note: The \ + update will proceed only after a successful backup.\");\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nA final report wi\ + th detailed information will be sent once the update process is completed.\ + \");\r\ + \n :set mailPtBodyAction (\$mailPtBodyAction . \"\\nIf you do not rec\ + eive a second email within the next 10 minutes, there may be an issue. Ple\ + ase check your device logs for further information.\");\r\ + \n }\r\ + \n :do {\r\ + \n :set mailAttachments [\$FuncCreateBackups \$backupName \$BackupPas\ + sword \$BackupSens];\r\ + \n :set mailPtSubjectBackup \"Backup created\";\r\ + \n :set mailPtBodyBackup \"System backups have been successfully crea\ + ted and attached to this email.\";\r\ + \n } on-error={\r\ + \n :set isOsNeedsToBeUpdated false;\r\ + \n :set mailPtSubjectBackup \"Backup failed\";\r\ + \n :set mailPtBodyBackup \"The script failed to create backups. Pleas\ + e check device logs for more details.\";\r\ + \n :log warning \"\$SMP Backup creation failed. Update process will b\ + e canceled if automatic update is enabled\";\r\ + \n }\r\ + \n }\r\ + \n :if (\$isEmailNeedsToBeSent = true) do={\r\ + \n :log info \"\$SMP Preparing to send email...\";\r\ + \n :local mailStep1Subject \$mailSubjectPrefix;\r\ + \n :local mailStep1Body \"\";\r\ + \n # subject\r\ + \n :if (\$mailSubjectPartAction != \"\") do={:set mailStep1Subject (\$\ + mailStep1Subject . \" - \" . \$mailSubjectPartAction)}\r\ + \n :if (\$mailPtSubjectBackup != \"\") do={:set mailStep1Subject (\$ma\ + ilStep1Subject . \" - \" . \$mailPtSubjectBackup)}\r\ + \n # body\r\ + \n :if (\$mailPtBodyAction != \"\") do={:set mailStep1Body (\$mailStep1\ + Body . \$mailPtBodyAction . \"\\n\\n\")}\r\ + \n :if (\$mailPtBodyBackup != \"\") do={:set mailStep1Body (\$mailStep1\ + Body . \$mailPtBodyBackup . \"\\n\\n\")}\r\ + \n :set mailStep1Body (\$mailStep1Body . \$mailBodyDeviceInfo . \"\\n__\ + ________\\n\" . \$mailBodyCopyright);\r\ + \n :set mailStep1Body (\$mailStep1Body . \"\\n[*** TEST START ***]\\n\\\ + \$DeviceInfo: \" . [ \$DeviceInfo ] . \"\\n[*** TEST END ***]\\n\");\r\ + \n # Send email with backups\r\ + \n :do {\$FuncSendEmailSafe \$EmailGeneralTo \$mailStep1Subject \$mailS\ + tep1Body \$mailAttachments} on-error={\r\ + \n :set isOsNeedsToBeUpdated false;\r\ + \n :log error \"\$SMP The script will not proceed with the update pro\ + cess, because the email was not sent.\";\r\ + \n }\r\ + \n }\r\ + \n :if ([:len \$mailAttachments] > 0) do={\r\ + \n :log info \"\$SMP Cleaning up backup files from the file system...\"\ + ;\r\ + \n /file remove \$mailAttachments;\r\ + \n :delay 2s;\r\ + \n }\r\ + \n :if (\$isOsNeedsToBeUpdated = true) do={\r\ + \n :global OldMode;\r\ + \n :log info \"\$SMP everything is ready to install new RouterOS, going\ + \_to start the update process and reboot the device.\";\r\ + \n :do {\r\ + \n :local nextStep 2;\r\ + \n :if (\$isCloudHostedRouter = true) do={\r\ + \n :log info \"\$SMP The device is a cloud hosted router, the secon\ + d step updating the Routerboard firmware will be skipped.\";\r\ + \n :set nextStep 3;\r\ + \n }\r\ + \n :local scheduledCommand (\":delay 5s; /system/scheduler remove BKP\ + UPD-NEXT-BOOT-TASK; \\\r\ + \n :global buGlobalVarScriptStep \$nextStep; :global buGlobalVarTarg\ + etOsVersion \\\"\$ROsVerAvail\\\"; \\\r\ + \n :delay 10s; /system/script { run \$ScriptName; }\");\r\ + \n /system/scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=\$schedu\ + ledCommand start-time=startup interval=0;\r\ + \n /system/package/update install;\r\ + \n } on-error={\r\ + \n # Failed to install new os version, remove the task and variables\ + \r\ + \n :do {\r\ + \n /system/scheduler remove BKPUPD-NEXT-BOOT-TASK;\r\ + \n :set BackupAndUpdateMode \$OldMode;\r\ + \n :delay 2;\r\ + \n :do {\r\ + \n :global buGlobalVarTargetOsVersion (a);\r\ + \n } on-error={\r\ + \n :set \$mailSubjectPrefix (\$mailSubjectPrefix . \"ERROR Remove\ + \_global variable \\\$buGlobalVarTargetOsVersion failed!\");\r\ + \n }\r\ + \n# :if ([ :len \$OldMode ] > 0) do={\r\ + \n# :do {\r\ + \n# :global OldMode (a);\r\ + \n# } on-error={\r\ + \n# :set \$mailSubjectPrefix (\$mailSubjectPrefix . \" ERROR Re\ + move global variable \\\$OldMode failed!\");\r\ + \n# }\r\ + \n# }\r\ + \n } on-error={\r\ + \n :log error \"\$SMP Failed to install new RouterOS version. Pleas\ + e check device logs for more details. \\\r\ + \n \\nAnd Failed to remove task and variables! Check it!\";\r\ + \n :set \$mailSubjectPrefix (\$mailSubjectPrefix . \" ERROR Remove \ + task and global variables!\");\r\ + \n }\r\ + \n :log error \"\$SMP Failed to install new RouterOS version. Please \ + check device logs for more details.\";\r\ + \n :local mailUpdateErrorSubject (\$mailSubjectPrefix . \" - Update f\ + ailed\");\r\ + \n :local mailUpdateErrorBody \"The script was unable to install new \ + RouterOS version. Please check device logs for more details.\";\r\ + \n # Send email with error\r\ + \n \$FuncSendEmailSafe \$EmailGeneralTo \$mailUpdateErrorSubject \$ma\ + ilUpdateErrorBody \"\";\r\ + \n :error \$exitErrorMessage;\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n## STEP 2: (Post-reboot) Upgrade RouterBOARD firmware\r\ + \n## Runs only if auto-update is enabled and a new RouterOS version was fo\ + und\r\ + \n:if (\$scriptStep = 2) do={\r\ + \n :log info \"\$SMP The script is in the second step, updating Routerboa\ + rd firmware.\";\r\ + \n :log info \"\$SMP Upgrading routerboard firmware from v.\$deviceRbCurr\ + entFw to v.\$deviceRbUpgradeFw\";\r\ + \n /system routerboard upgrade;\r\ + \n :delay 2;\r\ + \n :log info \"\$SMP routerboard upgrade process was completed, going to \ + reboot in a moment!\";\r\ + \n ## Set task to send final report on the next boot\r\ + \n /system scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=\":delay 2; \ + :global buGlobalVarScriptStep 3; \\\r\ + \n :global buGlobalVarTargetOsVersion \\\"\$buGlobalVarTargetOsVersion\\\ + \"; :delay 10s; /system/script { run \$ScriptName; }; \\ \r\ + \n :delay 5s; /system/scheduler remove BKPUPD-NEXT-BOOT-TASK;\" start-ti\ + me=startup interval=0;\r\ + \n :delay 2;\r\ + \n /system reboot;\r\ + \n}\r\ + \n\r\ + \n## STEP 3: Final report (after second reboot, with delay).\r\ + \n## Runs only if auto-update is enabled and a new RouterOS version was fo\ + und.\r\ + \n:if (\$scriptStep = 3) do={\r\ + \n :log info (\"\$SMP The script is in the third step, sending final repo\ + rt.\");\r\ + \n :local targetOsVersion \$buGlobalVarTargetOsVersion;\r\ + \n :do {\r\ + \n# /system/script/environment remove [find name=\"buGlobalVarTargetOsV\ + ersion\"];\r\ + \n :global buGlobalVarTargetOsVersion (a);\r\ + \n } on-error={\r\ + \n :set \$mailSubjectPrefix (\$mailSubjectPrefix . \" ERROR Remove glob\ + al variable \\\$buGlobalVarTargetOsVersion failed!\");\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$OldMode ] != 0) do={\r\ + \n :do {\r\ + \n# /system/script/environment remove [find name=\"OldMode\"];\r\ + \n :global OldMode (a);\r\ + \n } on-error={\r\ + \n :set \$mailSubjectPrefix (\$mailSubjectPrefix . \" ERROR! Remove\ + \_global variable \\\$OldMode failed!\");\r\ + \n }\r\ + \n }\r\ + \n :if ([:len \$targetOsVersion] = 0) do={\r\ + \n :log warning \"\$SMP Something is wrong, the script was unable to ge\ + t the target updated OS version from the global variable.\";\r\ + \n }\r\ + \n :local mailStep3Subject \$mailSubjectPrefix;\r\ + \n :local mailStep3Body \"\";\r\ + \n :if (\$targetOsVersion = \$runningVersion) do={\r\ + \n :log info \"\$SMP Successfully verified new RouterOS version: target\ + : `\$targetOsVersion`, current: `\$runningVersion`\";\r\ + \n :set mailStep3Subject (\$mailStep3Subject . \" - Update completed - \ + Backup created\");\r\ + \n :set mailStep3Body (\$mailStep3Body . \"RouterOS and routerboard upg\ + rade process was completed\");\r\ + \n :set mailStep3Body (\$mailStep3Body . \"\\nNew RouterOS version: v.\ + \$targetOsVersion, routerboard firmware: v.\$deviceRbCurrentFw\");\r\ + \n :set mailStep3Body (\$mailStep3Body . \"\\n\$changelogUrl\\nBackups \ + of the upgraded system are in the attachment of this email.\\n\\n\$mailBod\ + yDeviceInfo\\n\\n\$mailBodyCopyright\");\r\ + \n :set mailAttachments [\$FuncCreateBackups \$backupNameAfterUpdate \$\ + BackupPassword \$BackupSens];\r\ + \n } else={\r\ + \n :log error \"\$SMP Failed to verify new RouterOS version: target: `\ + \$targetOsVersion`, current: `\$runningVersion`\";\r\ + \n :set mailStep3Subject (\$mailStep3Subject . \" - Update failed\");\r\ + \n :set mailStep3Body (\$mailStep3Body . \"The script was unable to ver\ + ify that the new RouterOS version was installed, target version: `\$target\ + OsVersion`, current version: `\$runningVersion`\\nCheck device logs for mo\ + re details.\\n\\n\$mailBodyDeviceInfo\\n\\n\$mailBodyCopyright\");\r\ + \n }\r\ + \n \$FuncSendEmailSafe \$EmailGeneralTo \$mailStep3Subject \$mailStep3Bod\ + y \$mailAttachments;\r\ + \n :if ([:len \$mailAttachments] > 0) do={\r\ + \n :log info \"\$SMP Cleaning up backup files from the file system...\"\ + ;\r\ + \n /file remove \$mailAttachments;\r\ + \n :delay 2;\r\ + \n }\r\ + \n :log info (\"\$SMP Final report email sent successfully, and the scrip\ + t has finished.\");\r\ + \n}\r\ + \n:log info (\"\$SMP the script has finished, script step: `\$scriptStep` \ + \\n\\n\");\r\ + \n\r\ + \n} do={:global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err}\r\ + \n" +add dont-require-permissions=no name=testGetPubIP owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global DevInfoIncludeIP;\r\ + \n:global CharacterReplace;\r\ + \n:global EscapeForRegEx;\r\ + \n:global UrlEncode;\r\ + \n\r\ + \n:if ([ \$DevInfoIncludeIP ] = true) do={\r\ + \n :global GetPubIp;\r\ + \n :local Char (\"\\n\\r\");\r\ + \n :local PublicIpAddress [\$GetPubIp];\r\ + \n# :if ([ :pick \$PublicIpAddress ([ :len \$PublicIpAddress ] - 2) ] = \ + \"\\n\") do={:error true}; :set error falseon-error={:set PublicIpAddress \ + (\$PublicIpAddress . Char)};\r\ + \n#:if ([ :pick \$PublicIpAddress ([ :len \$PublicIpAddress ] - 1) ] = \"/\ + n\") do={\r\ + \n#:log warning \"N is = //n\"; \r\ + \n# :set PublicIpAddress [ \$CharacterReplace \$PublicIpAddress \$Char \"\ + \" ];\r\ + \n#}\r\ + \n# :set PublicIpAddress [ \$UrlEncode \$PublicIpAddress ];\r\ + \n#:local IpLen ([ :len \$PublicIpAddress ] -1);\r\ + \n#:set PublicIpAddress [:pick \$PublicIpAddress 0 \$IpLen];\r\ + \n :log warning \"Public IP address detected: \$PublicIpAddress , len = \ + \$IpLen\";\r\ + \n}\r\ + \n" +add comment="download, import and update firewall address-lists" \ + dont-require-permissions=no name=AM-FwAddrLists owner=AM-FwAddrLists \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-FwAddrLists\r\ + \n# Script comment: download, import and update firewall address-lists\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# https://ros.vados.ru/doc/fw-addr-lists.md\r\ + \n:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ + delay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n :global GlobalScriptsUrl;\r\ + \n :local ListsDirName (\"fw-addr-lists.d/\" . [ /system identity get nam\ + e ] . \"/\");\r\ + \n :local ListsUrl (\$GlobalScriptsUrl . \$ListsDirName);\r\ + \n :local ListsIndex \"index.lst\";\r\ + \n :local AddrListsTimeOut 1d;\r\ + \n :local CheckCerts false;\r\ + \n\r\ + \n :global CertificateAvailable;\r\ + \n :global EitherOr;\r\ + \n :global FetchHugeFiles;\r\ + \n :global HumanReadableNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global NetMask4;\r\ + \n :global NetMask6;\r\ + \n :global ScriptLock;\r\ + \n \r\ + \n :local FindDelim do={\r\ + \n :local ValidChars \"0123456789.:/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi\ + jklmnopqrstuvwxyz-\";\r\ + \n :for I from=0 to=[ :len \$1 ] do={\r\ + \n :if ([ :typeof [ :find \$ValidChars [ :pick (\$1 . \" \") \$I ] ] \ + ] != \"num\") do={\r\ + \n :return \$I;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local GetBranch do={\r\ + \n :global EitherOr;\r\ + \n :return [ :pick [ :convert transform=md5 to=hex [ :pick \$1 0 [ \$Ei\ + therOr [ :find \$1 \"/\" ] [ :len \$1 ] ] ] ] 0 2 ];\r\ + \n }\r\ + \n \r\ + \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local ListComment (\"managed by \" . \$ScriptName);\r\ + \n :local Url (\$ListsUrl . \$ListsIndex);\r\ + \n :local tmpIndex false;\r\ + \n\r\ + \n :for I from=1 to=5 do={\r\ + \n :if (\$tmpIndex = false) do={\r\ + \n :set tmpIndex [ :tolf [ \$FetchHugeFiles \$ScriptName \$Url \$Chec\ + kCerts ] ];\r\ + \n :if (\$tmpIndex = false && \$I < 5) do={\r\ + \n :log warning (\$ScriptName . \" Failed downloading address-list \ + index, \" . \$I . \". try from: \" . \$Url);\r\ + \n :delay ((\$I * \$I) . \"s\");\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :if (\$tmpIndex = false) do={\r\ + \n :log warning (\$ScriptName . \" Failed downloading address-list inde\ + x from: \" . \$Url);\r\ + \n :set tmpIndex \"\";\r\ + \n }\r\ + \n\r\ + \n :foreach List in=[ :deserialize \$tmpIndex delimiter=\"\\n\" from=dsv \ + options=dsv.plain ] do={\r\ + \n# :set List (\$List->0);\r\ + \n :local ListName;\r\ + \n :local Delim [ \$FindDelim \$List ];\r\ + \n :if (\$Delim = 0) do={ :set List \"\"; };\r\ + \n :log warning (\$ScriptName . \" Parsing address-list index entry: \"\ + \_. \$List);\r\ + \n :if ([ :len \$List ] = 0) do={\r\ + \n :log error (\$ScriptName . \" Failed parsing address-list index en\ + try: \" . \$List);\r\ + \n } else={\r\ + \n :set ListName [ :pick \$List 0 \$Delim ];\r\ + \n }\r\ + \n :log warning (\$ScriptName . \" Parsing address-list index entry: \"\ + \_. \$ListName . \" - Ok.\");\r\ + \n :local ListUrl (\$ListsUrl . \$ListName);\r\ + \n :local CntAdd 0;\r\ + \n :local CntRenew 0;\r\ + \n :local CntRemove 0;\r\ + \n :local IPv4Addresses ({});\r\ + \n :local IPv6Addresses ({});\r\ + \n :local Failure false;\r\ + \n :local Data false;\r\ + \n :local TimeOut \$AddrListTimeOut;\r\ + \n\r\ + \n :for I from=1 to=5 do={\r\ + \n :if (\$Data = false) do={\r\ + \n :set Data [ :tolf [ \$FetchHugeFiles \$ScriptName \$ListUrl \$Ch\ + eckCerts ] ];\r\ + \n :if (\$Data = false && \$I < 5) do={\r\ + \n :log warning (\$ScriptName . \" Failed downloading for list '\ + \" . \$ListName . \"', \" . \$I . \". try from: \" . \$ListUrl);\r\ + \n :delay ((\$I * \$I) . \"s\");\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if (\$Data = false) do={\r\ + \n :set Data \"\";\r\ + \n :set Failure true;\r\ + \n :log warning (\$ScriptName . \" Failed downloading for list '\" . \ + \$ListName . \"' from: \" . \$ListUrl);\r\ + \n } else={\r\ + \n :log warning (\$ScriptName . \" Downloaded \" . [ \$HumanReadableN\ + um [ :len \$Data ] 1024 ] . \"B for list '\" . \$ListName . \"' from: \" .\ + \_\$ListUrl);\r\ + \n }\r\ + \n\r\ + \n :foreach Line in=[ :deserialize \$Data delimiter=\"\\n\" from=dsv op\ + tions=dsv.plain ] do={\r\ + \n :set Line (\$Line->0);\r\ + \n :local Address;\r\ + \n :if ([ :pick \$Line 0 1 ] = \"{\" && [ :pick \$Line ([ :len \$Line\ + \_] - 1) ] = \"}\") do={\r\ + \n :do {\r\ + \n :set Address [ :tostr ([ :deserialize from=json \$Line ]->\"ci\ + dr\") ];\r\ + \n } on-error={ }\r\ + \n } else={\r\ + \n :set Address ([ :pick \$Line 0 [ \$FindDelim \$Line ] ] . (\$L\ + ist->\"cidr\"));\r\ + \n }\r\ + \n :do {\r\ + \n :local Branch;\r\ + \n :if (\$Address ~ \"^[0-9]{1,3}\\\\.[0-9]{1,3}\\\\.[0-9]{1,3}\\\\\ + .[0-9]{1,3}(/[0-9]{1,2})\?\\\$\") do={\r\ + \n :local Net \$Address;\r\ + \n :local CIDR 32;\r\ + \n :local Slash [ :find \$Address \"/\" ];\r\ + \n :if ([ :typeof \$Slash ] = \"num\") do={\r\ + \n :set Net [ :toip [ :pick \$Address 0 \$Slash ] ]\r\ + \n :set CIDR [ :pick \$Address (\$Slash + 1) [ :len \$Address ]\ + \_];\r\ + \n :set Address [ :tostr (([ :toip \$Net ] & [ \$NetMask4 \$CID\ + R ]) . [ \$IfThenElse (\$CIDR < 32) (\"/\" . \$CIDR) ]) ];\r\ + \n }\r\ + \n :set Branch [ \$GetBranch \$Address ];\r\ + \n :set (\$IPv4Addresses->\$Branch->\$Address) \$TimeOut;\r\ + \n }\r\ + \n :if (\$Address ~ \"^[0-9a-zA-Z]*:[0-9a-zA-Z:\\\\.]+(/[0-9]{1,3})\ + \?\\\$\") do={\r\ + \n :local Net \$Address;\r\ + \n :local CIDR 128;\r\ + \n :local Slash [ :find \$Address \"/\" ];\r\ + \n :if ([ :typeof \$Slash ] = \"num\") do={\r\ + \n :set Net [ :toip6 [ :pick \$Address 0 \$Slash ] ]\r\ + \n :set CIDR [ :pick \$Address (\$Slash + 1) [ :len \$Address ]\ + \_];\r\ + \n }\r\ + \n :set Address (([ :toip6 \$Net ] & [ \$NetMask6 \$CIDR ]) . \"/\ + \" . \$CIDR);\r\ + \n :set Branch [ \$GetBranch \$Address ];\r\ + \n :set (\$IPv6Addresses->\$Branch->\$Address) \$TimeOut;\r\ + \n }\r\ + \n :if (\$Address ~ \"^[\\\\.a-zA-Z0-9-]+\\\\.[a-zA-Z]{2,}\\\$\") d\ + o={\r\ + \n :set Branch [ \$GetBranch \$Address ];\r\ + \n :set (\$IPv4Addresses->\$Branch->\$Address) \$TimeOut;\r\ + \n :set (\$IPv6Addresses->\$Branch->\$Address) \$TimeOut;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n \r\ + \n\r\ + \n :foreach Entry in=[ /ip/firewall/address-list/find where \\\r\ + \n list=\$ListName comment=\$ListComment ] do={\r\ + \n :local Address [ /ip/firewall/address-list/get \$Entry address ];\ + \r\ + \n :local Branch [ \$GetBranch \$Address ];\r\ + \n :local TimeOut (\$IPv4Addresses->\$Branch->\$Address);\r\ + \n :if ([ :typeof \$TimeOut ] = \"time\") do={\r\ + \n :log warning (\$ScriptName . \" Renewing IPv4 address \" . \$Add\ + ress . \\\r\ + \n \" in list '\" . \$ListName . \"' with \" . \$TimeOut . \".\ + \");\r\ + \n /ip/firewall/address-list/set \$Entry timeout=\$TimeOut;\r\ + \n :set (\$IPv4Addresses->\$Branch->\$Address);\r\ + \n :set CntRenew (\$CntRenew + 1);\r\ + \n } else={\r\ + \n :if (\$Failure = false) do={\r\ + \n :log warning (\$ScriptName . \" Removing IPv4 address \" . \$A\ + ddress . \\\r\ + \n \" from list '\" . \$ListName . \".\");\r\ + \n /ip/firewall/address-list/remove \$Entry;\r\ + \n :set CntRemove (\$CntRemove + 1);\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :foreach Entry in=[ /ipv6/firewall/address-list/find where \\\r\ + \n list=\$ListName comment=\$ListComment ] do={\r\ + \n :local Address [ /ipv6/firewall/address-list/get \$Entry address ]\ + ;\r\ + \n :local Branch [ \$GetBranch \$Address ];\r\ + \n :local TimeOut (\$IPv6Addresses->\$Branch->\$Address);\r\ + \n :if ([ :typeof \$TimeOut ] = \"time\") do={\r\ + \n :log warning (\$ScriptName . \" Renewing IPv6 address \" . \$Add\ + ress . \\\r\ + \n \" in list '\" . \$ListName . \"' with \" . \$TimeOut . \".\ + \");\r\ + \n /ipv6/firewall/address-list/set \$Entry timeout=\$TimeOut;\r\ + \n :set (\$IPv6Addresses->\$Branch->\$Address);\r\ + \n :set CntRenew (\$CntRenew + 1);\r\ + \n } else={\r\ + \n :if (\$Failure = false) do={\r\ + \n :log warning (\$ScriptName . \" Removing IPv6 address \" . \$A\ + ddress . \\\r\ + \n \" from list '\" . \$ListName . \".\");\r\ + \n /ipv6/firewall/address-list/remove \$Entry;\r\ + \n :set CntRemove (\$CntRemove + 1);\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :foreach BranchName,Branch in=\$IPv4Addresses do={\r\ + \n :log warning (\$ScriptName . \" Handling branch: \" . \$BranchName\ + );\r\ + \n :foreach Address,Timeout in=\$Branch do={\r\ + \n :log warning (\$ScriptName . \" Adding IPv4 address \" . \$Addre\ + ss . \\\r\ + \n \" to list '\" . \$ListName . \"' with \" . \$Timeout . \".\ + \");\r\ + \n :onerror Err {\r\ + \n /ip/firewall/address-list/add list=\$ListName comment=\$ListCo\ + mment \\\r\ + \n address=\$Address timeout=\$Timeout;\r\ + \n :set CntAdd (\$CntAdd + 1);\r\ + \n } do={\r\ + \n :log warning (\$ScriptName . \" Failed to add IPv4 address \" \ + . \$Address . \\\r\ + \n \" to list '\" . \$ListName . \"': \" . \$Err);\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :foreach BranchName,Branch in=\$IPv6Addresses do={\r\ + \n :log warning (\$ScriptName . \" Handling branch: \" . \$BranchName\ + );\r\ + \n :foreach Address,Timeout in=\$Branch do={\r\ + \n :log warning (\$ScriptName . \" Adding IPv6 address \" . \$Addre\ + ss . \\\r\ + \n \" to list '\" . \$ListName . \"' with \" . \$Timeout . \".\ + \");\r\ + \n :onerror Err {\r\ + \n /ipv6/firewall/address-list/add list=\$ListName comment=\$List\ + Comment \\\r\ + \n address=\$Address timeout=\$Timeout;\r\ + \n :set CntAdd (\$CntAdd + 1);\r\ + \n } do={\r\ + \n :log warning (\$ScriptName . \" Failed to add IPv6 address \" \ + . \$Address . \\\r\ + \n \" to list '\" . \$ListName . \"': \" . \$Err);\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :log info (\$ScriptName . \" list: \" . \$ListName . \\\r\ + \n \" (\" . [ \$HumanReadableNum (\$CntAdd + \$CntRenew) 1000 ] . \ + \")\" . \\\r\ + \n \" -- added: \" . [ \$HumanReadableNum \$CntAdd 1000 ] . \\\r\ + \n \" - renewed: \" . [ \$HumanReadableNum \$CntRenew 1000 ] . \\\r\ + \n \" - removed: \" . [ \$HumanReadableNum \$CntRemove 1000 ]);\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ + \n}\r\ + \n" +add dont-require-permissions=no name=AmneziaWG owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + /routing table \ + \n#add disabled=no fib name=r_to_vpn\ + \n#/ip firewall address-list\ + \n#add address=8.8.4.4 list=to_vpn\ + \n#/ip firewall address-list\ + \n#add address=10.0.0.0/8 list=RFC1918\ + \n#add address=172.16.0.0/12 list=RFC1918\ + \n#add address=192.168.0.0/16 list=RFC1918\ + \n#/interface/list/add name=WAN\ + \n#/interface/list/member/add list=WAN interface=ether1\ + \n\ + \n/ip firewall mangle\ + \nadd action=accept chain=prerouting dst-address-list=RFC1918 in-interface\ + -list=!WAN\ + \n/ip firewall mangle\ + \nadd action=mark-connection chain=prerouting connection-mark=no-mark dst-\ + address-list=to_vpn in-interface-list=!WAN \\\ + \n new-connection-mark=to-vpn-conn passthrough=yes\ + \n/ip firewall mangle\ + \nadd action=mark-routing chain=prerouting connection-mark=to-vpn-conn in-\ + interface-list=!WAN new-routing-mark=r_to_vpn \\\ + \n passthrough=yes\ + \n/ip firewall mangle\ + \nadd action=mark-connection chain=output connection-mark=no-mark \\\ + \n dst-address-list=to_vpn new-connection-mark=to-vpn-conn-local \\\ + \n passthrough=yes\ + \nadd action=mark-routing chain=output connection-mark=to-vpn-conn-local \ + \\\ + \n new-routing-mark=r_to_vpn passthrough=yes\ + \n\ + \n" +/user group +add name=backup policy="telnet,ssh,ftp,read,write,policy,test,sniff,sensitive,\ + !local,!reboot,!winbox,!password,!web,!api,!romon,!rest-api" +/app +set cinny firewall-redirects=8094:80:tcp:web +set goaway container-command-lines=goaway:none:docker.io/pommee/goaway:latest +set home-assistant container-command-lines=\ + home-assistant:none:lscr.io/linuxserver/homeassistant +set n8n firewall-redirects=5678:5678:tcp:web +set nextcloud container-command-lines="db:none:docker.io/postgres:17,redis:non\ + e:docker.io/valkey/valkey:/bin/sh -c 'valkey-server --port 6379 --appendon\ + ly yes --requirepass \$VALKEY_PASSWORD',server:none:docker.io/nextcloud:ap\ + ache" +set pihole environment="pihole:FTLCONF_dns_listeningMode=all,pihole:FTLCONF_we\ + bserver_api_password=password" +set redlib firewall-redirects=8087:8080:tcp:web +set solr container-command-lines=solr:none:docker.io/solr:latest +set uptime-kuma container-command-lines=\ + uptime-kuma:none:docker.io/louislam/uptime-kuma:1 +/app settings +set auto-update=yes disk=*7 lan-bridge=Bridge-LAN registry-mirrors="https://re\ + g.vados.ru:5000/:https://reg.vados.ru/,https://registry-1.docker.io" +/caps-man aaa +set called-format=ssid +/caps-man access-list +add action=reject allow-signal-out-of-range=10s disabled=no interface=all \ + signal-range=-120..-80 ssid-regexp="" +add action=accept allow-signal-out-of-range=10s disabled=no interface=all \ + signal-range=-79..120 ssid-regexp="" +/caps-man manager +set ca-certificate=CAPsMAN-CA-51B25E507D07 certificate=CAPsMAN-51B25E507D07 \ + enabled=yes require-peer-certificate=yes +/caps-man manager interface +set [ find default=yes ] forbid=yes +add disabled=no interface=Bridge-LAN +/caps-man provisioning +add action=create-dynamic-enabled hw-supported-modes=g,gn,b \ + master-configuration=2G name-format=prefix-identity name-prefix=2G +add action=create-dynamic-enabled hw-supported-modes=an,ac,a \ + master-configuration=5G name-format=prefix-identity name-prefix=5G +add action=create-dynamic-enabled disabled=yes hw-supported-modes=ac,an,a \ + master-configuration=2G name-format=prefix-identity name-prefix=5ghz-ac +add action=create-dynamic-enabled disabled=yes hw-supported-modes=an \ + master-configuration=5G name-format=prefix-identity name-prefix=5ghz-an +/certificate settings +set builtin-trust-store=fetch crl-store=system +/container config +set layer-dir=/sata1 registry-url=https://reg.vados.ru tmpdir=/ramstorage \ + username=amster-dev +/container envs +add key=ENV list=carkeeperbot_envs value=/root/.ashrc +add key=PATH list=carkeeperbot_envs value=\ + /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +add key=PORT list=carkeeperbot_envs value="\${SSH_PORT}" +add key=SSH_PORT list=carkeeperbot_envs value=8222 +/container mounts +add dst=/etc/amnezia/amneziawg list=awg_conf src=/wg +add dst=/app list=carkeeper_app src=/sata1/carkeeper/app +add dst=/configs list=carkeeper_configs src=/sata1/carkeeper/configs +add dst=/root/.ashrc list=carkeeper_configs/.profile src=\ + /sata1/carkeeper/configs/.profile +add dst=/etc/php82/php.ini list=carkeeper_configs/php.ini src=\ + /sata1/carkeeper/configs/php.ini +add dst=/etc/ssh/sshd_config list=carkeeper_configs/sshd_config src=\ + /sata1/carkeeper/configs/sshd_config +add dst=/scripts list=carkeeper_scripts src=/sata1/carkeeper/scripts +add dst=/var/sync list=carkeeper_sync src=/sata1/carkeeper/sync +add dst=/var/tmp list=carkeeper_tmp src=/sata1/carkeeper/tmp +/interface bridge port +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-DOC interface=*B4 +add bridge=Bridge-LAN interface=LAN +add bridge=Bridge-LAN interface=dynamic +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes +/interface detect-internet +set detect-interface-list=all internet-interface-list=WAN lan-interface-list=\ + LAN wan-interface-list=WAN +/interface list member +add interface=Bridge-LAN list=WAN +add interface=lo list=LAN +/interface wifi capsman +set package-path=/tmpfs/capsman-packages upgrade-policy=none +/ip address +add address=10.30.30.10/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.10.10.1/24 disabled=yes interface=Bridge-DOC network=\ + 10.10.10.0 +add address=172.18.20.5/30 disabled=yes interface=*BA network=172.18.20.4 +add address=172.18.20.1/30 interface=*C3 network=172.18.20.0 +add address=172.18.20.1/30 interface=docker-awg-veth network=172.18.20.0 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set disabled=yes interface=Bridge-LAN \ + lease-script=lease-script lease-time=10m name=nucDHCP server-address=\ + 10.30.30.10 +/ip dns +set allow-remote-requests=yes doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=10.30.30.81 verify-doh-cert=yes +/ip firewall address-list +add address=8.8.4.4 list=to_vpn +add address=10.0.0.0/8 list=RFC1918 +add address=172.16.0.0/12 list=RFC1918 +add address=192.168.0.0/16 list=RFC1918 +/ip firewall filter +add action=accept chain=input +add action=accept chain=output +add action=accept chain=forward comment="Comment of the rule" disabled=yes +/ip firewall mangle +# docker-awg-veth not ready +add action=change-mss chain=forward new-mss=1360 out-interface=\ + docker-awg-veth protocol=tcp tcp-flags=syn tcp-mss=1420-65535 +/ip firewall nat +# docker-awg-veth not ready +add action=masquerade chain=srcnat out-interface=docker-awg-veth +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip route +add check-gateway=bfd disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + 10.30.30.81 routing-table=main scope=30 target-scope=10 +add distance=1 dst-address=0.0.0.0/0 gateway=172.18.20.2 routing-table=\ + r_to_vpn +add distance=1 dst-address=0.0.0.0/0 gateway=172.18.20.2 routing-table=\ + r_to_vpn +/ip service +set ftp disabled=yes +set www disabled=yes +set ssh port=2222 +set www-ssl port=4443 +set api disabled=yes +set api-ssl disabled=yes +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-plain=no rest-secure=no scep-plain=no \ + webfig-plain=no webfig-secure=no +/ip ssh +set forwarding-enabled=both password-authentication=no \ + publickey-authentication-options=verify-required strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=external +add interface=Bridge-DOC type=internal +/ipv6 firewall address-list +add address=2400:cb00::/32 list=CLOUDFLARE-IP-Address +add address=2606:4700::/32 list=CLOUDFLARE-IP-Address +add address=2803:f800::/32 list=CLOUDFLARE-IP-Address +add address=2405:b500::/32 list=CLOUDFLARE-IP-Address +add address=2405:8100::/32 list=CLOUDFLARE-IP-Address +add address=2a06:98c0::/29 list=CLOUDFLARE-IP-Address +add address=2c0f:f248::/32 list=CLOUDFLARE-IP-Address +/system clock +set time-zone-autodetect=no time-zone-name=Europe/Moscow +/system gps +set set-system-time=yes +/system identity +set name=MikroNUC +/system note +set show-at-login=no +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes +/system ntp client servers +add address=10.30.30.81 +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +/system scheduler +add comment="Every Day Set Global Environment Variables" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Fake Bridges" interval=1d name=\ + mod/AM-IPbridge on-event="/system/script/run mod/AM-IPbridge;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Telegram Chat Bot" interval=30s name=mod/AM-TG-Bot on-event=\ + "/system/script/run mod/AM-TG-Bot;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment=\ + "Every 7 Day Check For Update and Backup send notification to EMail." \ + interval=1w name=AM-Backup-UpdateEmail on-event=\ + "/system/script { run AM-Backup-UpdateEmail; }" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2026-06-25 start-time=03:41:27 +/tool e-mail +set certificate-verification=no from=MikroNUC port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool netwatch +add disabled=yes down-script=\ + ":local msg \"Host MikroYellow is DOWN\";\r\ + \n\$TGSendMessage \$msg;" host=10.30.30.86 http-codes="" interval=10s \ + test-script="" type=simple up-script=\ + ":global TGSendMessage;\r\ + \n\$TGSendMessage \"Host MikroYellow is UP\";" +/user aaa +set accounting=no diff --git a/MikroNUC/history/20260627/20260627232001-Diff-Config.rsc b/MikroNUC/history/20260627/20260627232001-Diff-Config.rsc new file mode 100644 index 0000000..b23d930 --- /dev/null +++ b/MikroNUC/history/20260627/20260627232001-Diff-Config.rsc @@ -0,0 +1,44 @@ +30a31,34 +> add address=172.18.20.6/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ +> gateway=172.18.20.5 gateway6="" name=docker-xray-vless-veth +> add address=10.10.10.10/24 container-mac-address=5C:26:FE:05:6F:12 dhcp=no \ +> gateway=10.10.10.1 gateway6="" mac-address=5C:26:FE:05:6F:11 name=veth1 +60a65 +> add slot=tmpfs tmpfs-max-size=715827882 type=tmpfs +4674,4675c4679,4680 +< set auto-update=yes disk=*7 lan-bridge=Bridge-LAN registry-mirrors="https://re\ +< g.vados.ru:5000/:https://reg.vados.ru/,https://registry-1.docker.io" +--- +> set auto-update=yes disk=sata1 lan-bridge=Bridge-LAN registry-mirrors="https:/\ +> /reg.vados.ru:5000/:https://reg.vados.ru/,https://registry-1.docker.io" +4724c4729 +< add bridge=Bridge-DOC interface=*B4 +--- +> add bridge=Bridge-DOC interface=veth1 +4741,4742c4746,4747 +< add address=172.18.20.5/30 disabled=yes interface=*BA network=172.18.20.4 +< add address=172.18.20.1/30 interface=*C3 network=172.18.20.0 +--- +> add address=172.18.20.5/30 disabled=yes interface=docker-xray-vless-veth \ +> network=172.18.20.4 +4761a4767,4780 +> # docker-xray-vless-veth not ready +> add action=change-mss chain=forward new-mss=1360 out-interface=\ +> docker-xray-vless-veth protocol=tcp tcp-flags=syn tcp-mss=1420-65535 +> add action=accept chain=prerouting dst-address-list=RFC1918 \ +> in-interface-list=!WAN +> add action=mark-connection chain=prerouting connection-mark=no-mark \ +> dst-address-list=to_vpn in-interface-list=!WAN new-connection-mark=\ +> to-vpn-conn +> add action=mark-routing chain=prerouting connection-mark=to-vpn-conn \ +> in-interface-list=!WAN new-routing-mark=r_to_vpn +> add action=mark-connection chain=output connection-mark=no-mark \ +> dst-address-list=to_vpn new-connection-mark=to-vpn-conn-local +> add action=mark-routing chain=output connection-mark=to-vpn-conn-local \ +> new-routing-mark=r_to_vpn +4765a4785,4786 +> # docker-xray-vless-veth not ready +> add action=masquerade chain=srcnat out-interface=docker-xray-vless-veth +4777,4778d4797 +< add distance=1 dst-address=0.0.0.0/0 gateway=172.18.20.2 routing-table=\ +< r_to_vpn -- 2.52.0