summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2015-11-23 10:46:52 -0800
committerAdam Ierymenko <adam.ierymenko@gmail.com>2015-11-23 10:46:52 -0800
commita18336fa1899a9f53b161a60e766695007c49a7b (patch)
treef464c0475ea49e3714df86d69508644adcf2e98a
parent1e4a40e77205b028d799f7112127f3f2f107117e (diff)
parent764dd1c3d94527c0870a913ac314b3b17eaea282 (diff)
downloadinfinitytier-a18336fa1899a9f53b161a60e766695007c49a7b.tar.gz
infinitytier-a18336fa1899a9f53b161a60e766695007c49a7b.zip
MERGE current "dev" into "netcon" -- should not affect netcon itself but will retest -- brings ZeroTier core up to 1.1.0
-rwxr-xr-x.gitignore29
-rw-r--r--README.md6
-rw-r--r--artwork/ZeroTierIcon512x512.pngbin0 -> 51309 bytes
-rw-r--r--attic/OSXEthernetTap.cpp.pcap-with-bridge-test651
-rw-r--r--attic/OSXEthernetTap.cpp.utun-work-in-progress832
-rw-r--r--attic/OSXEthernetTap.hpp.pcap-with-bridge-test96
-rw-r--r--attic/OSXEthernetTap.hpp.utun-work-in-progress101
-rw-r--r--cluster-geo/README.md14
-rwxr-xr-xcluster-geo/cluster-geo.exe13
-rw-r--r--cluster-geo/cluster-geo/cluster-geo.js102
-rw-r--r--cluster-geo/cluster-geo/config.js.sample7
-rw-r--r--cluster-geo/cluster-geo/package.json16
-rw-r--r--controller/SqliteNetworkController.cpp182
-rw-r--r--controller/SqliteNetworkController.hpp17
-rw-r--r--examples/api/README.md26
-rw-r--r--examples/api/circuit-test-pingpong.json13
-rw-r--r--examples/api/public.json27
-rw-r--r--examples/docker/Dockerfile19
-rw-r--r--examples/docker/README.md8
-rw-r--r--examples/docker/main.sh25
-rwxr-xr-xexamples/docker/maketestenv.sh11
-rw-r--r--ext/bin/miniupnpc/README.md4
-rw-r--r--ext/bin/miniupnpc/include/miniupnpc/minissdpc.h15
-rw-r--r--ext/bin/miniupnpc/linux-arm32/libminiupnpc.abin62698 -> 0 bytes
-rw-r--r--ext/bin/miniupnpc/linux-x64/libminiupnpc.abin87942 -> 0 bytes
-rw-r--r--ext/bin/miniupnpc/linux-x86/libminiupnpc.abin67782 -> 0 bytes
-rw-r--r--ext/bin/miniupnpc/mac-x64/libminiupnpc.abin95616 -> 0 bytes
-rw-r--r--ext/bin/miniupnpc/windows-x64/miniupnpc.libbin731616 -> 0 bytes
-rw-r--r--ext/bin/miniupnpc/windows-x86/miniupnpc.libbin702786 -> 0 bytes
-rw-r--r--ext/bin/tap-mac/tap.kext.old/Contents/Info.plist36
-rwxr-xr-xext/bin/tap-mac/tap.kext.old/Contents/MacOS/tapbin0 -> 81240 bytes
-rw-r--r--ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeDirectory (renamed from ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeDirectory)bin145 -> 145 bytes
-rw-r--r--ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeRequirements (renamed from ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeRequirements)bin176 -> 176 bytes
-rw-r--r--ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeResources105
-rw-r--r--ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeSignature (renamed from ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeSignature)bin8578 -> 8578 bytes
-rw-r--r--ext/bin/tap-mac/tap.kext/Contents/Info.plist2
-rwxr-xr-xext/bin/tap-mac/tap.kext/Contents/MacOS/tapbin81240 -> 50496 bytes
-rwxr-xr-xext/installfiles/linux/buildinstaller.sh2
-rwxr-xr-xext/installfiles/mac/launch.sh10
-rwxr-xr-xext/installfiles/mac/postinst.sh28
-rw-r--r--ext/installfiles/windows/ZeroTier One.aip34
-rw-r--r--ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Info.plist21
-rwxr-xr-xext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/MacOS/ZeroTier Onebin194640 -> 152736 bytes
-rw-r--r--ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/MainMenu.nibbin25733 -> 25269 bytes
-rw-r--r--ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/Window.nibbin3785 -> 3723 bytes
-rw-r--r--ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/_CodeSignature/CodeResources8
-rw-r--r--ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/project.pbxproj7
-rw-r--r--ext/mac-ui-macgap1-wrapper/src/MacGap/AppDelegate.m28
-rw-r--r--ext/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.m10
-rw-r--r--ext/mac-ui-macgap1-wrapper/src/MacGap/MacGap-Info.plist11
-rw-r--r--ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/Window.xib381
-rw-r--r--ext/miniupnpc/CMakeLists.txt178
-rw-r--r--ext/miniupnpc/Changelog.txt (renamed from ext/bin/miniupnpc/Changelog.txt)36
-rw-r--r--ext/miniupnpc/LICENSE (renamed from ext/bin/miniupnpc/LICENSE)0
-rw-r--r--ext/miniupnpc/MANIFEST.in5
-rw-r--r--ext/miniupnpc/Makefile379
-rw-r--r--ext/miniupnpc/Makefile.mingw98
-rw-r--r--ext/miniupnpc/README61
-rw-r--r--ext/miniupnpc/VERSION (renamed from ext/bin/miniupnpc/VERSION)0
-rw-r--r--ext/miniupnpc/apiversions.txt167
-rw-r--r--ext/miniupnpc/codelength.h (renamed from ext/bin/miniupnpc/include/miniupnpc/codelength.h)0
-rw-r--r--ext/miniupnpc/connecthostport.c266
-rw-r--r--ext/miniupnpc/connecthostport.h (renamed from ext/bin/miniupnpc/include/miniupnpc/connecthostport.h)0
-rwxr-xr-xext/miniupnpc/external-ip.sh4
-rw-r--r--ext/miniupnpc/igd_desc_parse.c123
-rw-r--r--ext/miniupnpc/igd_desc_parse.h (renamed from ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h)0
-rw-r--r--ext/miniupnpc/java/JavaBridgeTest.java97
-rwxr-xr-xext/miniupnpc/java/testjava.bat8
-rwxr-xr-xext/miniupnpc/java/testjava.sh8
-rw-r--r--ext/miniupnpc/listdevices.c110
-rw-r--r--ext/miniupnpc/man3/miniupnpc.355
-rw-r--r--ext/miniupnpc/mingw32make.bat8
-rw-r--r--ext/miniupnpc/minihttptestserver.c655
-rw-r--r--ext/miniupnpc/minisoap.c130
-rw-r--r--ext/miniupnpc/minisoap.h (renamed from ext/bin/miniupnpc/include/miniupnpc/minisoap.h)0
-rw-r--r--ext/miniupnpc/minissdpc.c851
-rw-r--r--ext/miniupnpc/minissdpc.h58
-rw-r--r--ext/miniupnpc/miniupnpc.c685
-rw-r--r--ext/miniupnpc/miniupnpc.def45
-rw-r--r--ext/miniupnpc/miniupnpc.h (renamed from ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h)50
-rw-r--r--ext/miniupnpc/miniupnpc_declspec.h (renamed from ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h)0
-rw-r--r--ext/miniupnpc/miniupnpcmodule.c695
-rw-r--r--ext/miniupnpc/miniupnpcstrings.h.cmake15
-rw-r--r--ext/miniupnpc/miniupnpcstrings.h.in (renamed from ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h)4
-rw-r--r--ext/miniupnpc/miniupnpctypes.h (renamed from ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h)0
-rw-r--r--ext/miniupnpc/miniwget.c633
-rw-r--r--ext/miniupnpc/miniwget.h (renamed from ext/bin/miniupnpc/include/miniupnpc/miniwget.h)0
-rw-r--r--ext/miniupnpc/minixml.c230
-rw-r--r--ext/miniupnpc/minixml.h (renamed from ext/bin/miniupnpc/include/miniupnpc/minixml.h)0
-rw-r--r--ext/miniupnpc/minixmlvalid.c164
-rw-r--r--ext/miniupnpc/msvc/miniupnpc.sln29
-rw-r--r--ext/miniupnpc/msvc/miniupnpc.vcproj283
-rw-r--r--ext/miniupnpc/msvc/upnpc-static.vcproj195
-rw-r--r--ext/miniupnpc/portlistingparse.c172
-rw-r--r--ext/miniupnpc/portlistingparse.h (renamed from ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h)0
-rw-r--r--ext/miniupnpc/pymoduletest.py88
-rw-r--r--ext/miniupnpc/receivedata.c105
-rw-r--r--ext/miniupnpc/receivedata.h (renamed from ext/bin/miniupnpc/include/miniupnpc/receivedata.h)0
-rw-r--r--ext/miniupnpc/setup.py28
-rw-r--r--ext/miniupnpc/setupmingw32.py28
-rw-r--r--ext/miniupnpc/testdesc/linksys_WAG200G_desc.values14
-rw-r--r--ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml110
-rw-r--r--ext/miniupnpc/testdesc/new_LiveBox_desc.values20
-rw-r--r--ext/miniupnpc/testdesc/new_LiveBox_desc.xml90
-rw-r--r--ext/miniupnpc/testigddescparse.c187
-rw-r--r--ext/miniupnpc/testminiwget.c53
-rwxr-xr-xext/miniupnpc/testminiwget.sh96
-rw-r--r--ext/miniupnpc/testminixml.c89
-rw-r--r--ext/miniupnpc/testportlistingparse.c151
-rw-r--r--ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue3
-rw-r--r--ext/miniupnpc/testreplyparse/DeletePortMapping.xml6
-rw-r--r--ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue2
-rw-r--r--ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml2
-rw-r--r--ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue3
-rw-r--r--ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml3
-rw-r--r--ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue5
-rw-r--r--ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml2
-rw-r--r--ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue1
-rw-r--r--ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml1
-rw-r--r--ext/miniupnpc/testreplyparse/readme.txt7
-rwxr-xr-xext/miniupnpc/testupnpigd.py84
-rw-r--r--ext/miniupnpc/testupnpreplyparse.c96
-rwxr-xr-xext/miniupnpc/testupnpreplyparse.sh14
-rwxr-xr-xext/miniupnpc/updateminiupnpcstrings.sh53
-rw-r--r--ext/miniupnpc/upnpc.c833
-rw-r--r--ext/miniupnpc/upnpcommands.c1238
-rw-r--r--ext/miniupnpc/upnpcommands.h (renamed from ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h)0
-rw-r--r--ext/miniupnpc/upnpdev.c23
-rw-r--r--ext/miniupnpc/upnpdev.h36
-rw-r--r--ext/miniupnpc/upnperrors.c107
-rw-r--r--ext/miniupnpc/upnperrors.h (renamed from ext/bin/miniupnpc/include/miniupnpc/upnperrors.h)0
-rw-r--r--ext/miniupnpc/upnpreplyparse.c198
-rw-r--r--ext/miniupnpc/upnpreplyparse.h (renamed from ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h)0
-rw-r--r--ext/miniupnpc/wingenminiupnpcstrings.c83
-rw-r--r--ext/tap-mac/tuntap/Makefile89
-rw-r--r--ext/tap-mac/tuntap/README.orig85
-rw-r--r--ext/tap-mac/tuntap/README.zerotier-build23
-rw-r--r--ext/tap-mac/tuntap/src/lock.cc15
-rw-r--r--ext/tap-mac/tuntap/src/tap/Makefile20
-rw-r--r--ext/tap-mac/tuntap/src/tap/tap.cc81
-rw-r--r--ext/tap-mac/tuntap/src/tap/tap.h14
-rw-r--r--ext/tap-mac/tuntap/src/tuntap.cc21
-rw-r--r--ext/tap-mac/tuntap/src/tuntap.h2
-rw-r--r--include/ZeroTierOne.h427
-rw-r--r--java/CMakeLists.txt1
-rw-r--r--java/build.xml53
-rw-r--r--java/jni/Android.mk7
-rw-r--r--java/jni/Application.mk9
-rw-r--r--java/jni/ZT1_jnicache.cpp242
-rw-r--r--java/jni/ZT_jnilookup.cpp158
-rw-r--r--java/jni/ZT_jnilookup.h (renamed from java/jni/ZT1_jnicache.h)23
-rw-r--r--java/jni/ZT_jniutils.cpp (renamed from java/jni/ZT1_jniutils.cpp)167
-rw-r--r--java/jni/ZT_jniutils.h (renamed from java/jni/ZT1_jniutils.h)0
-rw-r--r--java/jni/com_zerotierone_sdk_Node.cpp336
-rw-r--r--java/jni/com_zerotierone_sdk_Node.h4
-rw-r--r--java/src/com/zerotier/one/AndroidFileProvider.java43
-rw-r--r--java/src/com/zerotier/one/DataStore.java73
-rw-r--r--java/src/com/zerotier/one/DataStoreFileProvider.java12
-rw-r--r--java/src/com/zerotier/one/JavaFileProvider.java46
-rw-r--r--java/src/com/zerotier/one/OneService.java204
-rw-r--r--java/src/com/zerotier/sdk/Event.java25
-rw-r--r--java/src/com/zerotier/sdk/EventListener.java15
-rw-r--r--java/src/com/zerotier/sdk/MulticastGroup.java4
-rw-r--r--java/src/com/zerotier/sdk/Node.java4
-rw-r--r--java/src/com/zerotier/sdk/PacketSender.java9
-rw-r--r--java/src/com/zerotier/sdk/PeerRole.java8
-rw-r--r--java/src/com/zerotier/sdk/VirtualNetworkConfig.java38
-rw-r--r--make-freebsd.mk5
-rw-r--r--make-linux.mk56
-rw-r--r--make-mac.mk19
-rw-r--r--node/AntiRecursion.hpp73
-rw-r--r--node/BinarySemaphore.hpp106
-rw-r--r--node/Cluster.cpp913
-rw-r--r--node/Cluster.hpp418
-rw-r--r--node/Constants.hpp72
-rw-r--r--node/Defaults.cpp82
-rw-r--r--node/DeferredPackets.cpp95
-rw-r--r--node/DeferredPackets.hpp98
-rw-r--r--node/Hashtable.hpp9
-rw-r--r--node/Identity.cpp11
-rw-r--r--node/Identity.hpp21
-rw-r--r--node/IncomingPacket.cpp677
-rw-r--r--node/IncomingPacket.hpp40
-rw-r--r--node/InetAddress.cpp53
-rw-r--r--node/InetAddress.hpp143
-rw-r--r--node/Multicaster.cpp228
-rw-r--r--node/Multicaster.hpp2
-rw-r--r--node/Network.cpp123
-rw-r--r--node/Network.hpp5
-rw-r--r--node/NetworkConfig.cpp3
-rw-r--r--node/Node.cpp378
-rw-r--r--node/Node.hpp45
-rw-r--r--node/Packet.cpp15
-rw-r--r--node/Packet.hpp207
-rw-r--r--node/Path.cpp (renamed from node/Defaults.hpp)53
-rw-r--r--node/Path.hpp170
-rw-r--r--node/Peer.cpp340
-rw-r--r--node/Peer.hpp225
-rw-r--r--node/Poly1305.cpp314
-rw-r--r--node/RemotePath.hpp179
-rw-r--r--node/RuntimeEnvironment.hpp32
-rw-r--r--node/Salsa20.cpp1247
-rw-r--r--node/Salsa20.hpp43
-rw-r--r--node/SelfAwareness.cpp56
-rw-r--r--node/SelfAwareness.hpp10
-rw-r--r--node/SharedPtr.hpp33
-rw-r--r--node/Switch.cpp180
-rw-r--r--node/Switch.hpp7
-rw-r--r--node/Topology.cpp419
-rw-r--r--node/Topology.hpp152
-rw-r--r--node/Utils.cpp22
-rw-r--r--node/World.hpp241
-rw-r--r--objects.mk5
-rw-r--r--one.cpp72
-rw-r--r--osdep/Arp.cpp11
-rw-r--r--osdep/Arp.hpp5
-rw-r--r--osdep/OSUtils.cpp2
-rw-r--r--osdep/OSUtils.hpp1
-rw-r--r--osdep/Phy.hpp57
-rw-r--r--osdep/UPNPClient.cpp8
-rw-r--r--osdep/UPNPClient.hpp5
-rw-r--r--osdep/WindowsEthernetTap.cpp20
-rw-r--r--root-topology/Makefile17
-rw-r--r--root-topology/README.md18
-rw-r--r--root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c90
-rw-r--r--root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict4
-rw-r--r--root-topology/bin2c.c57
-rw-r--r--root-topology/mktopology.cpp68
-rw-r--r--root-topology/rootservers/7e19876aba4
-rw-r--r--root-topology/rootservers/8841408a2e4
-rw-r--r--root-topology/rootservers/8acf059fe34
-rw-r--r--root-topology/rootservers/9d219039f34
-rw-r--r--root-topology/test/README.md6
-rwxr-xr-xroot-topology/test/create-test-root-topology.sh31
-rw-r--r--selftest.cpp90
-rw-r--r--service/ClusterDefinition.hpp125
-rw-r--r--service/ClusterGeoIpService.cpp197
-rw-r--r--service/ClusterGeoIpService.hpp94
-rw-r--r--service/ControlPlane.cpp44
-rw-r--r--service/OneService.cpp214
-rw-r--r--service/OneService.hpp7
-rw-r--r--tests/http/2015-11-10_01_50000.out.xzbin0 -> 730360 bytes
-rw-r--r--tests/http/2015-11-10_02_50000.out.xzbin0 -> 2373664 bytes
-rw-r--r--tests/http/2015-11-10_03_12500_ec2-east-only.out.xzbin0 -> 802932 bytes
-rw-r--r--tests/http/Dockerfile24
-rw-r--r--tests/http/README.md12
-rw-r--r--tests/http/agent.js196
-rwxr-xr-xtests/http/big-test-kill.sh9
-rwxr-xr-xtests/http/big-test-start.sh13
-rw-r--r--tests/http/crunch-results.js65
-rwxr-xr-xtests/http/docker-main.sh16
-rw-r--r--tests/http/nodesource-el.repo6
-rw-r--r--tests/http/package.json16
-rw-r--r--tests/http/server.js53
-rw-r--r--ui/ZeroTierNetwork.jsx24
-rw-r--r--ui/ZeroTierNode.jsx74
-rw-r--r--ui/zerotier.css100
-rw-r--r--ui/ztui.min.js2
-rw-r--r--version.h4
-rw-r--r--windows/TapDriver/TapDriver.vcxproj385
-rw-r--r--windows/TapDriver/TapDriver.vcxproj.filters75
-rw-r--r--windows/TapDriver/config.h12
-rw-r--r--windows/TapDriver/constants.h51
-rw-r--r--windows/TapDriver/endian.h35
-rw-r--r--windows/TapDriver/error.c387
-rw-r--r--windows/TapDriver/error.h88
-rw-r--r--windows/TapDriver/instance.c241
-rw-r--r--windows/TapDriver/lock.h75
-rw-r--r--windows/TapDriver/macinfo.c154
-rw-r--r--windows/TapDriver/macinfo.h38
-rw-r--r--windows/TapDriver/mem.c186
-rw-r--r--windows/TapDriver/proto.h60
-rw-r--r--windows/TapDriver/prototypes.h163
-rw-r--r--windows/TapDriver/tap-windows.h69
-rw-r--r--windows/TapDriver/tapdrvr.c2183
-rw-r--r--windows/TapDriver/types.h137
-rw-r--r--windows/TapDriver/zttap200.inf78
-rw-r--r--windows/WebUIWrapper/Form1.Designer.cs66
-rw-r--r--windows/WebUIWrapper/Form1.cs74
-rw-r--r--windows/WebUIWrapper/Form1.resx6293
-rw-r--r--windows/WebUIWrapper/Program.cs92
-rw-r--r--windows/WebUIWrapper/Properties/AssemblyInfo.cs36
-rw-r--r--windows/WebUIWrapper/Properties/Settings.settings7
-rw-r--r--windows/WinUI/APIHandler.cs208
-rw-r--r--windows/WinUI/App.config (renamed from windows/WebUIWrapper/App.config)0
-rw-r--r--windows/WinUI/App.xaml14
-rw-r--r--windows/WinUI/App.xaml.cs17
-rw-r--r--windows/WinUI/Fonts/segoeui.ttfbin0 -> 910308 bytes
-rw-r--r--windows/WinUI/Fonts/segoeuib.ttfbin0 -> 898564 bytes
-rw-r--r--windows/WinUI/Fonts/segoeuii.ttfbin0 -> 508344 bytes
-rw-r--r--windows/WinUI/Fonts/segoeuiz.ttfbin0 -> 522076 bytes
-rw-r--r--windows/WinUI/MainWindow.xaml132
-rw-r--r--windows/WinUI/MainWindow.xaml.cs195
-rw-r--r--windows/WinUI/NetworkInfoView.xaml73
-rw-r--r--windows/WinUI/NetworkInfoView.xaml.cs72
-rw-r--r--windows/WinUI/NetworksPage.xaml13
-rw-r--r--windows/WinUI/NetworksPage.xaml.cs52
-rw-r--r--windows/WinUI/PeersPage.xaml26
-rw-r--r--windows/WinUI/PeersPage.xaml.cs54
-rw-r--r--windows/WinUI/Properties/AssemblyInfo.cs56
-rw-r--r--windows/WinUI/Properties/Resources.Designer.cs (renamed from windows/WebUIWrapper/Properties/Resources.Designer.cs)46
-rw-r--r--windows/WinUI/Properties/Resources.resx (renamed from windows/WebUIWrapper/Properties/Resources.resx)0
-rw-r--r--windows/WinUI/Properties/Settings.Designer.cs (renamed from windows/WebUIWrapper/Properties/Settings.Designer.cs)22
-rw-r--r--windows/WinUI/Properties/Settings.settings7
-rw-r--r--windows/WinUI/Simple Styles.xaml1121
-rw-r--r--windows/WinUI/Themes/Generic.xaml7
-rw-r--r--windows/WinUI/WinUI.csproj (renamed from windows/WebUIWrapper/WebUIWrapper.csproj)161
-rw-r--r--windows/WinUI/ZeroTierIcon.ico (renamed from windows/WebUIWrapper/ZeroTierIcon.ico)bin370070 -> 370070 bytes
-rw-r--r--windows/WinUI/ZeroTierNetwork.cs54
-rw-r--r--windows/WinUI/ZeroTierPeer.cs116
-rw-r--r--windows/WinUI/ZeroTierPeerPhysicalPath.cs27
-rw-r--r--windows/WinUI/ZeroTierStatus.cs39
-rw-r--r--windows/WinUI/app.manifest (renamed from windows/WebUIWrapper/Properties/app.manifest)15
-rw-r--r--windows/WinUI/packages.config4
-rw-r--r--windows/ZeroTierOne.sln261
-rw-r--r--windows/ZeroTierOne/ZeroTierOne.vcxproj67
-rw-r--r--windows/ZeroTierOne/ZeroTierOne.vcxproj.filters129
-rw-r--r--windows/packages/.gitignore3
-rw-r--r--windows/packages/repositories.config4
-rw-r--r--world/README.md7
-rwxr-xr-xworld/build.sh1
-rw-r--r--world/earth-2015-11-16.binbin0 -> 494 bytes
-rw-r--r--world/earth-2015-11-20.binbin0 -> 792 bytes
-rw-r--r--world/mkworld.cpp187
324 files changed, 23670 insertions, 15514 deletions
diff --git a/.gitignore b/.gitignore
index 498119e3..0ddbbb88 100755
--- a/.gitignore
+++ b/.gitignore
@@ -29,8 +29,12 @@ Thumbs.db
# *nix/Mac build droppings
/build-*
/ZeroTierOneInstaller-*
+/examples/docker/zerotier-one
+/examples/docker/test-*.env
+/world/mkworld
+/world/*.c25519
-# Miscellaneous file types that we don't want to check in
+# Miscellaneous temporaries, build files, etc.
*.log
*.opensdf
*.user
@@ -40,28 +44,26 @@ Thumbs.db
*.pid
*.pkg
*.o
+*.a
+*.dylib
+*.so
+*.o-*
*.core
*.deb
*.rpm
*.autosave
*.tmp
-
-# Root topology build files, temporaries, and never check in secrets
-/root-topology/bin2c
-/root-topology/mktopology
-/root-topology/*.secret
-/root-topology/test/supernodes
-/root-topology/test/test-root-topology
+node_modules
+cluster-geo/cluster-geo/config.js
+cluster-geo/cluster-geo/cache.*
+tests/http/zerotier-one
+tests/http/big-test-hosts
# MacGap wrapper build files
/ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/project.xcworkspace/xcuserdata/*
/ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/xcuserdata/*
/ext/mac-ui-macgap1-wrapper/src/build
-# Web UI dev temporaries
-/ui/.module-cache
-node_modules
-
# Java/Android/JNI build droppings
java/obj/
java/libs/
@@ -71,3 +73,6 @@ java/doc/
java/build_win64/
java/build_win32/
/java/mac32_64/
+windows/WinUI/obj/
+windows/WinUI/bin/
+windows/ZeroTierOne/Debug/
diff --git a/README.md b/README.md
index 24806504..123fbf01 100644
--- a/README.md
+++ b/README.md
@@ -116,7 +116,7 @@ On Mac the best way is to install [Packages](http://s.sudre.free.fr/Software/Pac
This builds a .pkg file that can be installed.
-BSD has no installer yet. We're working on it.
+In FreeBSD there is now an official .pkg in the FreeBSD repository. Type "pkg install zerotier". It can also be built and installed from source.
Linux/BSD and Mac installations have an *uninstall.sh* file in their ZeroTier home folder that cleanly removes ZeroTier One from the system. Run this with:
@@ -166,6 +166,10 @@ If you're interested, there's a [technical deep dive about NAT traversal on our
If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity.
+### Contributing
+
+There are three main branches: **edge**, **test**, and **master**. Other branches may be for specific features, tests, or use cases. In general **edge** is "bleeding" and may or may not work, while **test** should be relatively stable and **master** is the latest tagged release. Pull requests should generally be done against **test** or **edge**, since pull requests against **master** may be working against a branch that is somewhat out of date.
+
### License
The ZeroTier source code is open source and is licensed under the GNU GPL v3 (not LGPL). If you'd like to embed it in a closed-source commercial product or appliance, please e-mail [contact@zerotier.com](mailto:contact@zerotier.com) to discuss commercial licensing. Otherwise it can be used for free.
diff --git a/artwork/ZeroTierIcon512x512.png b/artwork/ZeroTierIcon512x512.png
new file mode 100644
index 00000000..d225c2e3
--- /dev/null
+++ b/artwork/ZeroTierIcon512x512.png
Binary files differ
diff --git a/attic/OSXEthernetTap.cpp.pcap-with-bridge-test b/attic/OSXEthernetTap.cpp.pcap-with-bridge-test
new file mode 100644
index 00000000..60194421
--- /dev/null
+++ b/attic/OSXEthernetTap.cpp.pcap-with-bridge-test
@@ -0,0 +1,651 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <signal.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/select.h>
+#include <sys/cdefs.h>
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <netinet6/in6_var.h>
+#include <netinet/in_var.h>
+#include <netinet/icmp6.h>
+
+#include <pcap/pcap.h>
+
+// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!?
+struct prf_ra {
+ u_char onlink : 1;
+ u_char autonomous : 1;
+ u_char reserved : 6;
+} prf_ra;
+
+#include <netinet6/nd6.h>
+#include <ifaddrs.h>
+
+// These are KERNEL_PRIVATE... why?
+#ifndef SIOCAUTOCONF_START
+#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */
+#endif
+#ifndef SIOCAUTOCONF_STOP
+#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */
+#endif
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+// This source is from:
+// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt
+// It's here because OSX 10.6 does not have this convenience function.
+
+#define SALIGN (sizeof(uint32_t) - 1)
+#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
+(SALIGN + 1))
+#define MAX_SYSCTL_TRY 5
+#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
+
+/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from <sys/socket.h> */
+/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */
+//#define DARWIN_COMPAT
+
+//#ifdef DARWIN_COMPAT
+#define GIM_SYSCTL_MIB NET_RT_IFLIST2
+#define GIM_RTM_ADDR RTM_NEWMADDR2
+//#else
+//#define GIM_SYSCTL_MIB NET_RT_IFMALIST
+//#define GIM_RTM_ADDR RTM_NEWMADDR
+//#endif
+
+// Not in 10.6 includes so use our own
+struct _intl_ifmaddrs {
+ struct _intl_ifmaddrs *ifma_next;
+ struct sockaddr *ifma_name;
+ struct sockaddr *ifma_addr;
+ struct sockaddr *ifma_lladdr;
+};
+
+static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
+{
+ int icnt = 1;
+ int dcnt = 0;
+ int ntry = 0;
+ size_t len;
+ size_t needed;
+ int mib[6];
+ int i;
+ char *buf;
+ char *data;
+ char *next;
+ char *p;
+ struct ifma_msghdr2 *ifmam;
+ struct _intl_ifmaddrs *ifa, *ift;
+ struct rt_msghdr *rtm;
+ struct sockaddr *sa;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = GIM_SYSCTL_MIB;
+ mib[5] = 0; /* no flags */
+ do {
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return (-1);
+ if ((buf = (char *)malloc(needed)) == NULL)
+ return (-1);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ free(buf);
+ return (-1);
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case GIM_RTM_ADDR:
+ ifmam = (struct ifma_msghdr2 *)(void *)rtm;
+ if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
+ break;
+ icnt++;
+ p = (char *)(ifmam + 1);
+ for (i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifmam->ifmam_addrs &
+ (1 << i)) == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ dcnt += len;
+ p += len;
+ }
+ break;
+ }
+ }
+
+ data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
+ if (data == NULL) {
+ free(buf);
+ return (-1);
+ }
+
+ ifa = (struct _intl_ifmaddrs *)(void *)data;
+ data += sizeof(struct _intl_ifmaddrs) * icnt;
+
+ memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt);
+ ift = ifa;
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+
+ switch (rtm->rtm_type) {
+ case GIM_RTM_ADDR:
+ ifmam = (struct ifma_msghdr2 *)(void *)rtm;
+ if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
+ break;
+
+ p = (char *)(ifmam + 1);
+ for (i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifmam->ifmam_addrs &
+ (1 << i)) == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ switch (i) {
+ case RTAX_GATEWAY:
+ ift->ifma_lladdr =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_IFP:
+ ift->ifma_name =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_IFA:
+ ift->ifma_addr =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ default:
+ data += len;
+ break;
+ }
+ p += len;
+ }
+ ift->ifma_next = ift + 1;
+ ift = ift->ifma_next;
+ break;
+ }
+ }
+
+ free(buf);
+
+ if (ift > ifa) {
+ ift--;
+ ift->ifma_next = NULL;
+ *pif = ifa;
+ } else {
+ *pif = NULL;
+ free(ifa);
+ }
+ return (0);
+}
+
+static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
+{
+ free(ifmp);
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+#include <string>
+#include <map>
+#include <set>
+#include <algorithm>
+
+#include "../node/Constants.hpp"
+#include "../node/Utils.hpp"
+#include "../node/Mutex.hpp"
+#include "../node/Dictionary.hpp"
+#include "OSUtils.hpp"
+#include "OSXEthernetTap.hpp"
+
+// ff:ff:ff:ff:ff:ff with no ADI
+static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
+
+static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts)
+{
+ struct in6_ndireq nd;
+ struct in6_ifreq ifr;
+
+ int s = socket(AF_INET6,SOCK_DGRAM,0);
+ if (s <= 0)
+ return false;
+
+ memset(&nd,0,sizeof(nd));
+ strncpy(nd.ifname,ifname,sizeof(nd.ifname));
+
+ if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
+ close(s);
+ return false;
+ }
+
+ unsigned long oldFlags = (unsigned long)nd.ndi.flags;
+
+ if (performNUD)
+ nd.ndi.flags |= ND6_IFF_PERFORMNUD;
+ else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
+
+ if (oldFlags != (unsigned long)nd.ndi.flags) {
+ if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) {
+ close(s);
+ return false;
+ }
+ }
+
+ memset(&ifr,0,sizeof(ifr));
+ strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name));
+ if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) {
+ close(s);
+ return false;
+ }
+
+ close(s);
+ return true;
+}
+
+namespace ZeroTier {
+
+static std::set<std::string> globalDeviceNames;
+static Mutex globalTapCreateLock;
+
+OSXEthernetTap::OSXEthernetTap(
+ const char *homePath,
+ const MAC &mac,
+ unsigned int mtu,
+ unsigned int metric,
+ uint64_t nwid,
+ const char *friendlyName,
+ void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len),
+ void *arg) :
+ _handler(handler),
+ _arg(arg),
+ _pcap((void *)0),
+ _nwid(nwid),
+ _mac(mac),
+ _homePath(homePath),
+ _mtu(mtu),
+ _metric(metric),
+ _enabled(true)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+ char devname[64],ethaddr[64],mtustr[32],metstr[32],nwids[32];
+
+ Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid);
+
+ if (mtu > 2800)
+ throw std::runtime_error("max tap MTU is 2800");
+
+ Mutex::Lock _gl(globalTapCreateLock);
+
+ std::string desiredDevice;
+ Dictionary devmap;
+ {
+ std::string devmapbuf;
+ if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) {
+ devmap.fromString(devmapbuf);
+ desiredDevice = devmap.get(nwids,"");
+ }
+ }
+
+ if ((desiredDevice.length() >= 9)&&(desiredDevice.substr(0,6) == "bridge")) {
+ // length() >= 9 matches bridge### or bridge####
+ _dev = desiredDevice;
+ } else {
+ if (globalDeviceNames.size() >= (10000 - 128)) // sanity check... this would be nuts
+ throw std::runtime_error("too many devices!");
+ unsigned int pseudoBridgeNo = (unsigned int)((nwid ^ (nwid >> 32)) % (10000 - 128)) + 128; // range: bridge128 to bridge9999
+ sprintf(devname,"bridge%u",pseudoBridgeNo);
+ while (globalDeviceNames.count(std::string(devname)) > 0) {
+ ++pseudoBridgeNo;
+ if (pseudoBridgeNo > 9999)
+ pseudoBridgeNo = 64;
+ sprintf(devname,"bridge%u",pseudoBridgeNo);
+ }
+ _dev = devname;
+ }
+
+ // Configure MAC address and MTU, bring interface up
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"create",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ if (exitcode != 0)
+ throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
+ } else throw std::runtime_error("unable to fork()");
+ Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]);
+ Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu);
+ Utils::snprintf(metstr,sizeof(metstr),"%u",_metric);
+ cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ if (exitcode != 0)
+ throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
+ } else throw std::runtime_error("unable to fork()");
+
+ _setIpv6Stuff(_dev.c_str(),true,false);
+
+ _pcap = (void *)pcap_create(_dev.c_str(),errbuf);
+ if (!_pcap) {
+ cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ }
+ throw std::runtime_error((std::string("pcap_create() on new bridge device failed: ") + errbuf).c_str());
+ }
+ pcap_set_promisc(reinterpret_cast<pcap_t *>(_pcap),1);
+ pcap_set_timeout(reinterpret_cast<pcap_t *>(_pcap),120000);
+ pcap_set_immediate_mode(reinterpret_cast<pcap_t *>(_pcap),1);
+ if (pcap_set_buffer_size(reinterpret_cast<pcap_t *>(_pcap),1024 * 1024 * 16) != 0) // 16MB
+ fprintf(stderr,"WARNING: pcap_set_buffer_size() failed!\n");
+ if (pcap_set_snaplen(reinterpret_cast<pcap_t *>(_pcap),4096) != 0)
+ fprintf(stderr,"WARNING: pcap_set_snaplen() failed!\n");
+ if (pcap_activate(reinterpret_cast<pcap_t *>(_pcap)) != 0) {
+ pcap_close(reinterpret_cast<pcap_t *>(_pcap));
+ cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ }
+ throw std::runtime_error("pcap_activate() on new bridge device failed.");
+ }
+
+ globalDeviceNames.insert(_dev);
+
+ devmap[nwids] = _dev;
+ OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmap.toString());
+
+ _thread = Thread::start(this);
+}
+
+OSXEthernetTap::~OSXEthernetTap()
+{
+ _enabled = false;
+
+ Mutex::Lock _gl(globalTapCreateLock);
+ globalDeviceNames.erase(_dev);
+
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ if (exitcode == 0) {
+ // Destroying the interface nukes pcap and terminates the thread.
+ Thread::join(_thread);
+ }
+ }
+
+ pcap_close(reinterpret_cast<pcap_t *>(_pcap));
+}
+
+static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
+{
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0);
+ _exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ waitpid(cpid,&exitcode,0);
+ return (exitcode == 0);
+ }
+ return false; // never reached, make compiler shut up about return value
+}
+
+bool OSXEthernetTap::addIp(const InetAddress &ip)
+{
+ if (!ip)
+ return false;
+
+ std::vector<InetAddress> allIps(ips());
+ if (std::binary_search(allIps.begin(),allIps.end(),ip))
+ return true;
+
+ // Remove and reconfigure if address is the same but netmask is different
+ for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
+ if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
+ if (___removeIp(_dev,*i))
+ break;
+ }
+ }
+
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ return (exitcode == 0);
+ } // else return false...
+
+ return false;
+}
+
+bool OSXEthernetTap::removeIp(const InetAddress &ip)
+{
+ if (!ip)
+ return true;
+ std::vector<InetAddress> allIps(ips());
+ if (!std::binary_search(allIps.begin(),allIps.end(),ip)) {
+ if (___removeIp(_dev,ip))
+ return true;
+ }
+ return false;
+}
+
+std::vector<InetAddress> OSXEthernetTap::ips() const
+{
+ struct ifaddrs *ifa = (struct ifaddrs *)0;
+ if (getifaddrs(&ifa))
+ return std::vector<InetAddress>();
+
+ std::vector<InetAddress> r;
+
+ struct ifaddrs *p = ifa;
+ while (p) {
+ if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
+ switch(p->ifa_addr->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
+ struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
+ r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
+ } break;
+ case AF_INET6: {
+ struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
+ struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
+ uint32_t b[4];
+ memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
+ r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
+ } break;
+ }
+ }
+ p = p->ifa_next;
+ }
+
+ if (ifa)
+ freeifaddrs(ifa);
+
+ std::sort(r.begin(),r.end());
+ std::unique(r.begin(),r.end());
+
+ return r;
+}
+
+void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
+{
+ char putBuf[4096];
+ if ((len <= _mtu)&&(_enabled)) {
+ to.copyTo(putBuf,6);
+ from.copyTo(putBuf + 6,6);
+ *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
+ memcpy(putBuf + 14,data,len);
+ len += 14;
+ int r = pcap_inject(reinterpret_cast<pcap_t *>(_pcap),putBuf,len);
+ if (r <= 0) {
+ printf("%s: pcap_inject() failed\n",_dev.c_str());
+ return;
+ }
+ printf("%s: inject %s -> %s etherType==%u len=%u r==%d\n",_dev.c_str(),from.toString().c_str(),to.toString().c_str(),etherType,len,r);
+ }
+}
+
+std::string OSXEthernetTap::deviceName() const
+{
+ return _dev;
+}
+
+void OSXEthernetTap::setFriendlyName(const char *friendlyName)
+{
+}
+
+void OSXEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
+{
+ std::vector<MulticastGroup> newGroups;
+
+ struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0;
+ if (!_intl_getifmaddrs(&ifmap)) {
+ struct _intl_ifmaddrs *p = ifmap;
+ while (p) {
+ if (p->ifma_addr->sa_family == AF_LINK) {
+ struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
+ struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
+ if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
+ newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
+ }
+ p = p->ifma_next;
+ }
+ _intl_freeifmaddrs(ifmap);
+ }
+
+ std::vector<InetAddress> allIps(ips());
+ for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
+ newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
+
+ std::sort(newGroups.begin(),newGroups.end());
+ std::unique(newGroups.begin(),newGroups.end());
+
+ for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
+ if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
+ added.push_back(*m);
+ }
+ for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
+ if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
+ removed.push_back(*m);
+ }
+
+ _multicastGroups.swap(newGroups);
+}
+
+static void _pcapHandler(u_char *ptr,const struct pcap_pkthdr *hdr,const u_char *data)
+{
+ OSXEthernetTap *tap = reinterpret_cast<OSXEthernetTap *>(ptr);
+ if (hdr->caplen > 14) {
+ MAC to(data,6);
+ MAC from(data + 6,6);
+ if (from == tap->_mac) {
+ unsigned int etherType = ntohs(((const uint16_t *)data)[6]);
+ printf("%s: %s -> %s etherType==%u len==%u\n",tap->_dev.c_str(),from.toString().c_str(),to.toString().c_str(),etherType,(unsigned int)hdr->caplen);
+ // TODO: VLAN support
+ tap->_handler(tap->_arg,tap->_nwid,from,to,etherType,0,(const void *)(data + 14),hdr->len - 14);
+ }
+ }
+}
+
+void OSXEthernetTap::threadMain()
+ throw()
+{
+ pcap_loop(reinterpret_cast<pcap_t *>(_pcap),-1,&_pcapHandler,reinterpret_cast<u_char *>(this));
+}
+
+} // namespace ZeroTier
diff --git a/attic/OSXEthernetTap.cpp.utun-work-in-progress b/attic/OSXEthernetTap.cpp.utun-work-in-progress
new file mode 100644
index 00000000..b7a05334
--- /dev/null
+++ b/attic/OSXEthernetTap.cpp.utun-work-in-progress
@@ -0,0 +1,832 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <signal.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/select.h>
+#include <sys/cdefs.h>
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sys_domain.h>
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <netinet6/in6_var.h>
+#include <netinet/in_var.h>
+#include <netinet/icmp6.h>
+
+// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!?
+struct prf_ra {
+ u_char onlink : 1;
+ u_char autonomous : 1;
+ u_char reserved : 6;
+} prf_ra;
+
+#include <netinet6/nd6.h>
+#include <ifaddrs.h>
+
+// These are KERNEL_PRIVATE... why?
+#ifndef SIOCAUTOCONF_START
+#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */
+#endif
+#ifndef SIOCAUTOCONF_STOP
+#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */
+#endif
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+// This source is from:
+// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt
+// It's here because OSX 10.6 does not have this convenience function.
+
+#define SALIGN (sizeof(uint32_t) - 1)
+#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
+(SALIGN + 1))
+#define MAX_SYSCTL_TRY 5
+#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
+
+/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from <sys/socket.h> */
+/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */
+//#define DARWIN_COMPAT
+
+//#ifdef DARWIN_COMPAT
+#define GIM_SYSCTL_MIB NET_RT_IFLIST2
+#define GIM_RTM_ADDR RTM_NEWMADDR2
+//#else
+//#define GIM_SYSCTL_MIB NET_RT_IFMALIST
+//#define GIM_RTM_ADDR RTM_NEWMADDR
+//#endif
+
+// Not in 10.6 includes so use our own
+struct _intl_ifmaddrs {
+ struct _intl_ifmaddrs *ifma_next;
+ struct sockaddr *ifma_name;
+ struct sockaddr *ifma_addr;
+ struct sockaddr *ifma_lladdr;
+};
+
+static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
+{
+ int icnt = 1;
+ int dcnt = 0;
+ int ntry = 0;
+ size_t len;
+ size_t needed;
+ int mib[6];
+ int i;
+ char *buf;
+ char *data;
+ char *next;
+ char *p;
+ struct ifma_msghdr2 *ifmam;
+ struct _intl_ifmaddrs *ifa, *ift;
+ struct rt_msghdr *rtm;
+ struct sockaddr *sa;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = GIM_SYSCTL_MIB;
+ mib[5] = 0; /* no flags */
+ do {
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return (-1);
+ if ((buf = (char *)malloc(needed)) == NULL)
+ return (-1);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ free(buf);
+ return (-1);
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case GIM_RTM_ADDR:
+ ifmam = (struct ifma_msghdr2 *)(void *)rtm;
+ if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
+ break;
+ icnt++;
+ p = (char *)(ifmam + 1);
+ for (i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifmam->ifmam_addrs &
+ (1 << i)) == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ dcnt += len;
+ p += len;
+ }
+ break;
+ }
+ }
+
+ data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
+ if (data == NULL) {
+ free(buf);
+ return (-1);
+ }
+
+ ifa = (struct _intl_ifmaddrs *)(void *)data;
+ data += sizeof(struct _intl_ifmaddrs) * icnt;
+
+ memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt);
+ ift = ifa;
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+
+ switch (rtm->rtm_type) {
+ case GIM_RTM_ADDR:
+ ifmam = (struct ifma_msghdr2 *)(void *)rtm;
+ if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
+ break;
+
+ p = (char *)(ifmam + 1);
+ for (i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifmam->ifmam_addrs &
+ (1 << i)) == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ switch (i) {
+ case RTAX_GATEWAY:
+ ift->ifma_lladdr =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_IFP:
+ ift->ifma_name =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_IFA:
+ ift->ifma_addr =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ default:
+ data += len;
+ break;
+ }
+ p += len;
+ }
+ ift->ifma_next = ift + 1;
+ ift = ift->ifma_next;
+ break;
+ }
+ }
+
+ free(buf);
+
+ if (ift > ifa) {
+ ift--;
+ ift->ifma_next = NULL;
+ *pif = ifa;
+ } else {
+ *pif = NULL;
+ free(ifa);
+ }
+ return (0);
+}
+
+static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
+{
+ free(ifmp);
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+#include <string>
+#include <map>
+#include <set>
+#include <algorithm>
+
+#include "../node/Constants.hpp"
+#include "../node/Utils.hpp"
+#include "../node/Mutex.hpp"
+#include "../node/Dictionary.hpp"
+#include "Arp.hpp"
+#include "OSUtils.hpp"
+#include "OSXEthernetTap.hpp"
+
+// ff:ff:ff:ff:ff:ff with no ADI
+static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
+
+static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts)
+{
+ struct in6_ndireq nd;
+ struct in6_ifreq ifr;
+
+ int s = socket(AF_INET6,SOCK_DGRAM,0);
+ if (s <= 0)
+ return false;
+
+ memset(&nd,0,sizeof(nd));
+ strncpy(nd.ifname,ifname,sizeof(nd.ifname));
+
+ if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
+ close(s);
+ return false;
+ }
+
+ unsigned long oldFlags = (unsigned long)nd.ndi.flags;
+
+ if (performNUD)
+ nd.ndi.flags |= ND6_IFF_PERFORMNUD;
+ else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
+
+ if (oldFlags != (unsigned long)nd.ndi.flags) {
+ if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) {
+ close(s);
+ return false;
+ }
+ }
+
+ memset(&ifr,0,sizeof(ifr));
+ strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name));
+ if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) {
+ close(s);
+ return false;
+ }
+
+ close(s);
+ return true;
+}
+
+// Create an OSX-native utun device (utun# where # is desiredNumber)
+// Adapted from public domain utun example code by Jonathan Levin
+static int _make_utun(int desiredNumber)
+{
+ struct sockaddr_ctl sc;
+ struct ctl_info ctlInfo;
+ struct ifreq ifr;
+
+ memset(&ctlInfo, 0, sizeof(ctlInfo));
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= sizeof(ctlInfo.ctl_name)) {
+ return -1;
+ }
+
+ int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (fd == -1)
+ return -1;
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+ sc.sc_unit = desiredNumber + 1;
+
+ if (connect(fd, (struct sockaddr *)&sc, sizeof(sc)) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ memset(&ifr,0,sizeof(ifr));
+ sprintf(ifr.ifr_name,"utun%d",desiredNumber);
+ if (ioctl(fd,SIOCGIFFLAGS,(void *)&ifr) < 0) {
+ printf("SIOCGIFFLAGS failed\n");
+ }
+ ifr.ifr_flags &= ~IFF_POINTOPOINT;
+ if (ioctl(fd,SIOCSIFFLAGS,(void *)&ifr) < 0) {
+ printf("clear IFF_POINTOPOINT failed\n");
+ }
+
+ return fd;
+}
+
+namespace ZeroTier {
+
+static long globalTapsRunning = 0;
+static Mutex globalTapCreateLock;
+
+OSXEthernetTap::OSXEthernetTap(
+ const char *homePath,
+ const MAC &mac,
+ unsigned int mtu,
+ unsigned int metric,
+ uint64_t nwid,
+ const char *friendlyName,
+ void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len),
+ void *arg) :
+ _handler(handler),
+ _arg(arg),
+ _arp((Arp *)0),
+ _nwid(nwid),
+ _homePath(homePath),
+ _mtu(mtu),
+ _metric(metric),
+ _fd(0),
+ _utun(false),
+ _enabled(true)
+{
+ char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32];
+ struct stat stattmp;
+
+ Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid);
+
+ if (mtu > 2800)
+ throw std::runtime_error("max tap MTU is 2800");
+
+ Mutex::Lock _gl(globalTapCreateLock);
+
+ // Read remembered previous device name, if any -- we'll try to reuse
+ Dictionary devmap;
+ std::string desiredDevice;
+ {
+ std::string devmapbuf;
+ if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) {
+ devmap.fromString(devmapbuf);
+ desiredDevice = devmap.get(nwids,"");
+ }
+ }
+
+ if (::stat((_homePath + ZT_PATH_SEPARATOR_S + "tap.kext").c_str(),&stattmp) == 0) {
+ // Try to init kext if it's there, otherwise revert to utun mode
+
+ if (::stat("/dev/zt0",&stattmp)) {
+ long kextpid = (long)vfork();
+ if (kextpid == 0) {
+ ::chdir(homePath);
+ OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
+ ::execl("/sbin/kextload","/sbin/kextload","-q","-repository",homePath,"tap.kext",(const char *)0);
+ ::_exit(-1);
+ } else if (kextpid > 0) {
+ int exitcode = -1;
+ ::waitpid(kextpid,&exitcode,0);
+ }
+ ::usleep(500); // give tap device driver time to start up and try again
+ if (::stat("/dev/zt0",&stattmp))
+ _utun = true;
+ }
+
+ if (!_utun) {
+ // See if we can re-use the last device we had.
+ bool recalledDevice = false;
+ if (desiredDevice.length() > 2) {
+ Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",desiredDevice.c_str());
+ if (stat(devpath,&stattmp) == 0) {
+ _fd = ::open(devpath,O_RDWR);
+ if (_fd > 0) {
+ _dev = desiredDevice;
+ recalledDevice = true;
+ }
+ }
+ }
+
+ // Open the first unused tap device if we didn't recall a previous one.
+ if (!recalledDevice) {
+ for(int i=0;i<64;++i) {
+ Utils::snprintf(devpath,sizeof(devpath),"/dev/zt%d",i);
+ if (stat(devpath,&stattmp)) {
+ _utun = true;
+ break;
+ }
+ _fd = ::open(devpath,O_RDWR);
+ if (_fd > 0) {
+ char foo[16];
+ Utils::snprintf(foo,sizeof(foo),"zt%d",i);
+ _dev = foo;
+ break;
+ }
+ }
+ }
+ if (_fd <= 0)
+ _utun = true;
+ }
+ } else {
+ _utun = true;
+ }
+
+ if (_utun) {
+ // Use OSX built-in utun device if kext is not available or doesn't work
+
+ int utunNo = 0;
+
+ if ((desiredDevice.length() > 4)&&(desiredDevice.substr(0,4) == "utun")) {
+ utunNo = Utils::strToInt(desiredDevice.substr(4).c_str());
+ if (utunNo >= 0)
+ _fd = _make_utun(utunNo);
+ }
+
+ if (_fd <= 0) {
+ // Start at utun8 to leave lower utuns unused since other stuff might
+ // want them -- OpenVPN, cjdns, etc. I'm not sure if those are smart
+ // enough to scan upward like this.
+ for(utunNo=8;utunNo<=256;++utunNo) {
+ if ((_fd = _make_utun(utunNo)) > 0)
+ break;
+ }
+ }
+
+ if (_fd <= 0)
+ throw std::runtime_error("unable to find/load ZeroTier tap driver OR use built-in utun driver in OSX; permission or system problem or too many open devices?");
+
+ Utils::snprintf(devpath,sizeof(devpath),"utun%d",utunNo);
+ _dev = devpath;
+
+ // Configure address and bring it up
+ Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu);
+ Utils::snprintf(metstr,sizeof(metstr),"%u",_metric);
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",mtustr,"metric",metstr,"up",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ if (exitcode) {
+ ::close(_fd);
+ throw std::runtime_error("ifconfig failure activating utun interface");
+ }
+ }
+
+ } else {
+ // Use our ZeroTier OSX tun/tap driver for zt# Ethernet tap device
+
+ if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) {
+ ::close(_fd);
+ throw std::runtime_error("unable to set flags on file descriptor for TAP device");
+ }
+
+ // Configure MAC address and MTU, bring interface up
+ Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]);
+ Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu);
+ Utils::snprintf(metstr,sizeof(metstr),"%u",_metric);
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ if (exitcode) {
+ ::close(_fd);
+ throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
+ }
+ }
+
+ _setIpv6Stuff(_dev.c_str(),true,false);
+ }
+
+ // Set close-on-exec so that devices cannot persist if we fork/exec for update
+ fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
+
+ ::pipe(_shutdownSignalPipe);
+
+ ++globalTapsRunning;
+
+ devmap[nwids] = _dev;
+ OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmap.toString());
+
+ _thread = Thread::start(this);
+}
+
+OSXEthernetTap::~OSXEthernetTap()
+{
+ Mutex::Lock _gl(globalTapCreateLock);
+
+ ::write(_shutdownSignalPipe[1],(const void *)this,1); // writing a byte causes thread to exit
+ Thread::join(_thread);
+
+ ::close(_fd);
+ ::close(_shutdownSignalPipe[0]);
+ ::close(_shutdownSignalPipe[1]);
+
+ if (_utun) {
+ delete _arp;
+ } else {
+ if (--globalTapsRunning <= 0) {
+ globalTapsRunning = 0; // sanity check -- should not be possible
+
+ char tmp[16384];
+ sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext");
+ long kextpid = (long)vfork();
+ if (kextpid == 0) {
+ OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
+ ::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0);
+ ::_exit(-1);
+ } else if (kextpid > 0) {
+ int exitcode = -1;
+ ::waitpid(kextpid,&exitcode,0);
+ }
+ }
+ }
+}
+
+void OSXEthernetTap::setEnabled(bool en)
+{
+ _enabled = en;
+ // TODO: interface status change
+}
+
+bool OSXEthernetTap::enabled() const
+{
+ return _enabled;
+}
+
+static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
+{
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0);
+ _exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ waitpid(cpid,&exitcode,0);
+ return (exitcode == 0);
+ }
+ return false; // never reached, make compiler shut up about return value
+}
+
+bool OSXEthernetTap::addIp(const InetAddress &ip)
+{
+ if (!ip)
+ return false;
+
+ std::vector<InetAddress> allIps(ips());
+ if (std::binary_search(allIps.begin(),allIps.end(),ip))
+ return true;
+
+ // Remove and reconfigure if address is the same but netmask is different
+ for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
+ if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
+ if (___removeIp(_dev,*i))
+ break;
+ }
+ }
+
+ if (_utun) {
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ if (ip.ss_family == AF_INET6) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet6",ip.toString().c_str(),"alias",(const char *)0);
+ } else {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.toString().c_str(),ip.toIpString().c_str(),"alias",(const char *)0);
+ }
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+
+ if (exitcode == 0) {
+ if (ip.ss_family == AF_INET) {
+ // Add route to network over tun for IPv4 -- otherwise it behaves
+ // as a simple point to point tunnel instead of a true route.
+ cpid = (long)vfork();
+ if (cpid == 0) {
+ ::close(STDERR_FILENO);
+ ::close(STDOUT_FILENO);
+ ::execl("/sbin/route","/sbin/route","add",ip.network().toString().c_str(),ip.toIpString().c_str(),(const char *)0);
+ ::exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ return (exitcode == 0);
+ }
+ } else return true;
+ }
+ }
+ } else {
+ long cpid = (long)vfork();
+ if (cpid == 0) {
+ ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0);
+ ::_exit(-1);
+ } else if (cpid > 0) {
+ int exitcode = -1;
+ ::waitpid(cpid,&exitcode,0);
+ return (exitcode == 0);
+ }
+ }
+
+ return false;
+}
+
+bool OSXEthernetTap::removeIp(const InetAddress &ip)
+{
+ if (!ip)
+ return true;
+ std::vector<InetAddress> allIps(ips());
+ if (!std::binary_search(allIps.begin(),allIps.end(),ip)) {
+ if (___removeIp(_dev,ip))
+ return true;
+ }
+ return false;
+}
+
+std::vector<InetAddress> OSXEthernetTap::ips() const
+{
+ struct ifaddrs *ifa = (struct ifaddrs *)0;
+ if (getifaddrs(&ifa))
+ return std::vector<InetAddress>();
+
+ std::vector<InetAddress> r;
+
+ struct ifaddrs *p = ifa;
+ while (p) {
+ if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
+ switch(p->ifa_addr->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
+ struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
+ r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
+ } break;
+ case AF_INET6: {
+ struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
+ struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
+ uint32_t b[4];
+ memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
+ r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
+ } break;
+ }
+ }
+ p = p->ifa_next;
+ }
+
+ if (ifa)
+ freeifaddrs(ifa);
+
+ std::sort(r.begin(),r.end());
+ std::unique(r.begin(),r.end());
+
+ return r;
+}
+
+void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
+{
+ char putBuf[4096];
+ if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
+ to.copyTo(putBuf,6);
+ from.copyTo(putBuf + 6,6);
+ *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
+ memcpy(putBuf + 14,data,len);
+ len += 14;
+ ::write(_fd,putBuf,len);
+ }
+}
+
+std::string OSXEthernetTap::deviceName() const
+{
+ return _dev;
+}
+
+void OSXEthernetTap::setFriendlyName(const char *friendlyName)
+{
+}
+
+void OSXEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
+{
+ std::vector<MulticastGroup> newGroups;
+
+ struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0;
+ if (!_intl_getifmaddrs(&ifmap)) {
+ struct _intl_ifmaddrs *p = ifmap;
+ while (p) {
+ if (p->ifma_addr->sa_family == AF_LINK) {
+ struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
+ struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
+ if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
+ newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
+ }
+ p = p->ifma_next;
+ }
+ _intl_freeifmaddrs(ifmap);
+ }
+
+ std::vector<InetAddress> allIps(ips());
+ for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
+ newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
+
+ std::sort(newGroups.begin(),newGroups.end());
+ std::unique(newGroups.begin(),newGroups.end());
+
+ for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
+ if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
+ added.push_back(*m);
+ }
+ for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
+ if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
+ removed.push_back(*m);
+ }
+
+ _multicastGroups.swap(newGroups);
+}
+
+void OSXEthernetTap::threadMain()
+ throw()
+{
+ fd_set readfds,nullfds;
+ MAC to,from;
+ int n,nfds,r;
+ char getBuf[8194];
+
+ Thread::sleep(500);
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&nullfds);
+ nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
+
+ r = 0;
+ for(;;) {
+ FD_SET(_shutdownSignalPipe[0],&readfds);
+ FD_SET(_fd,&readfds);
+ select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
+
+ if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
+ break;
+
+ if (FD_ISSET(_fd,&readfds)) {
+ n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r);
+ if (n < 0) {
+ if ((errno != EINTR)&&(errno != ETIMEDOUT))
+ break;
+ } else {
+ // Some tap drivers like to send the ethernet frame and the
+ // payload in two chunks, so handle that by accumulating
+ // data until we have at least a frame.
+ r += n;
+ if (r > 14) {
+ if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
+ r = _mtu + 14;
+
+ if (_enabled) {
+ to.setTo(getBuf,6);
+ from.setTo(getBuf + 6,6);
+ unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
+ // TODO: VLAN support
+ _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14);
+ }
+
+ r = 0;
+ }
+ }
+ }
+ }
+}
+
+} // namespace ZeroTier
diff --git a/attic/OSXEthernetTap.hpp.pcap-with-bridge-test b/attic/OSXEthernetTap.hpp.pcap-with-bridge-test
new file mode 100644
index 00000000..33f1948c
--- /dev/null
+++ b/attic/OSXEthernetTap.hpp.pcap-with-bridge-test
@@ -0,0 +1,96 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_OSXETHERNETTAP_HPP
+#define ZT_OSXETHERNETTAP_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "../node/Constants.hpp"
+#include "../node/MAC.hpp"
+#include "../node/InetAddress.hpp"
+#include "../node/MulticastGroup.hpp"
+
+#include "Thread.hpp"
+
+namespace ZeroTier {
+
+/**
+ * OSX Ethernet tap using ZeroTier kernel extension zt# devices
+ */
+class OSXEthernetTap
+{
+public:
+ OSXEthernetTap(
+ const char *homePath,
+ const MAC &mac,
+ unsigned int mtu,
+ unsigned int metric,
+ uint64_t nwid,
+ const char *friendlyName,
+ void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
+ void *arg);
+
+ ~OSXEthernetTap();
+
+ inline void setEnabled(bool en) { _enabled = en; }
+ inline bool enabled() const { return _enabled; }
+ bool addIp(const InetAddress &ip);
+ bool removeIp(const InetAddress &ip);
+ std::vector<InetAddress> ips() const;
+ void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
+ std::string deviceName() const;
+ void setFriendlyName(const char *friendlyName);
+ void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
+
+ void threadMain()
+ throw();
+
+ // Private members of OSXEthernetTap have public visibility to be accessable
+ // from an internal bounce function; don't modify directly.
+ void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
+ void *_arg;
+ void *_pcap; // pcap_t *
+ uint64_t _nwid;
+ MAC _mac;
+ Thread _thread;
+ std::string _homePath;
+ std::string _dev;
+ std::vector<MulticastGroup> _multicastGroups;
+ unsigned int _mtu;
+ unsigned int _metric;
+ volatile bool _enabled;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/attic/OSXEthernetTap.hpp.utun-work-in-progress b/attic/OSXEthernetTap.hpp.utun-work-in-progress
new file mode 100644
index 00000000..8ece87b3
--- /dev/null
+++ b/attic/OSXEthernetTap.hpp.utun-work-in-progress
@@ -0,0 +1,101 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_OSXETHERNETTAP_HPP
+#define ZT_OSXETHERNETTAP_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "../node/Constants.hpp"
+#include "../node/MAC.hpp"
+#include "../node/InetAddress.hpp"
+#include "../node/MulticastGroup.hpp"
+
+#include "Thread.hpp"
+
+namespace ZeroTier {
+
+class Arp;
+
+/**
+ * OSX Ethernet tap supporting either ZeroTier tun/tap kext or OSX-native utun
+ */
+class OSXEthernetTap
+{
+public:
+ OSXEthernetTap(
+ const char *homePath,
+ const MAC &mac,
+ unsigned int mtu,
+ unsigned int metric,
+ uint64_t nwid,
+ const char *friendlyName,
+ void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
+ void *arg);
+
+ ~OSXEthernetTap();
+
+ void setEnabled(bool en);
+ bool enabled() const;
+ bool addIp(const InetAddress &ip);
+ bool removeIp(const InetAddress &ip);
+ std::vector<InetAddress> ips() const;
+ void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
+ std::string deviceName() const;
+ void setFriendlyName(const char *friendlyName);
+ void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
+
+ inline bool isNativeUtun() const { return _utun; }
+
+ void threadMain()
+ throw();
+
+private:
+ void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
+ void *_arg;
+ Arp *_arp; // created and used if utun is enabled
+ uint64_t _nwid;
+ Thread _thread;
+ std::string _homePath;
+ std::string _dev;
+ std::vector<MulticastGroup> _multicastGroups;
+ unsigned int _mtu;
+ unsigned int _metric;
+ int _fd;
+ int _shutdownSignalPipe[2];
+ bool _utun;
+ volatile bool _enabled;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/cluster-geo/README.md b/cluster-geo/README.md
new file mode 100644
index 00000000..492ffc0d
--- /dev/null
+++ b/cluster-geo/README.md
@@ -0,0 +1,14 @@
+Cluster GeoIP Service
+======
+
+In cluster mode (build with ZT\_ENABLE\_CLUSTER and install a cluster definition file), ZeroTier One can use geographic IP lookup to steer clients toward members of a cluster that are physically closer and are therefore very likely to offer lower latency and better performance. Ordinary non-clustered ZeroTier endpoints will have no use for this code.
+
+If a cluster-mode instance detects a file in the ZeroTier home folder called *cluster-geo.exe*, it attempts to execute it. If this program runs, it receives IP addresses on STDIN and produces lines of CSV on STDOUT with the following format:
+
+ IP,result code,latitude,longitude,x,y,z
+
+The first field is the IP echoed back. The second field is 0 if the result is pending and may be ready in the future or 1 if the result is ready now. If the second field is 0 the remaining fields should be 0. Otherwise the remaining fields contain the IP's latitude, longitude, and X/Y/Z coordinates.
+
+ZeroTier's cluster route optimization code only uses the X/Y/Z values. These are computed by this cluster-geo code as the spherical coordinates of the IP address using the Earth's center as the point of origin and using an approximation of the Earth as a sphere. This doesn't yield *exact* coordinates, but it's good enough for our purposes since the goal is to route clients to the geographically closest endpoint.
+
+To install, copy *cluster-geo.exe* and the *cluster-geo/* subfolder into the ZeroTier home. Then go into *cluster-geo/* and run *npm install* to install the project's dependencies. A recent (4.x or newer) version of NodeJS is recommended. You will also need a [MaxMind GeoIP2 Precision Services](https://www.maxmind.com/) license key. The *MaxMind GeoIP2 City* tier is required since this supplies actual coordinates. It's a commercial service but is very inexpensive and offers very good accuracy for both IPv4 and IPv6 addresses. The *cluster-geo.js* program caches results in a LevelDB database for up to 120 days to reduce GeoIP API queries.
diff --git a/cluster-geo/cluster-geo.exe b/cluster-geo/cluster-geo.exe
new file mode 100755
index 00000000..56b76e0d
--- /dev/null
+++ b/cluster-geo/cluster-geo.exe
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin
+
+cd `dirname $0`
+if [ ! -d cluster-geo -o ! -f cluster-geo/cluster-geo.js ]; then
+ echo 'Cannot find ./cluster-geo containing NodeJS script files.'
+ exit 1
+fi
+
+cd cluster-geo
+
+exec node --harmony cluster-geo.js
diff --git a/cluster-geo/cluster-geo/cluster-geo.js b/cluster-geo/cluster-geo/cluster-geo.js
new file mode 100644
index 00000000..3cbc60be
--- /dev/null
+++ b/cluster-geo/cluster-geo/cluster-geo.js
@@ -0,0 +1,102 @@
+"use strict";
+
+//
+// GeoIP lookup service
+//
+
+// GeoIP cache TTL in ms
+var CACHE_TTL = (60 * 60 * 24 * 120 * 1000); // 120 days
+
+// Globally increase event emitter maximum listeners
+//var EventEmitter = require('events');
+//EventEmitter.prototype._maxListeners = 1000;
+//process.setMaxListeners(1000);
+
+// Load config
+var config = require(__dirname + '/config.js');
+
+if (!config.maxmind) {
+ console.error('FATAL: only MaxMind GeoIP2 is currently supported and is not configured in config.js');
+ process.exit(1);
+}
+var geo = require('geoip2ws')(config.maxmind);
+
+var cache = require('levelup')(__dirname + '/cache.leveldb');
+
+function lookup(ip,callback)
+{
+ cache.get(ip,function(err,cachedEntryJson) {
+ if ((!err)&&(cachedEntryJson)) {
+ try {
+ let cachedEntry = JSON.parse(cachedEntryJson.toString());
+ if (cachedEntry) {
+ let ts = cachedEntry.ts;
+ let r = cachedEntry.r;
+ if ((ts)&&(r)) {
+ if ((Date.now() - ts) < CACHE_TTL) {
+ r._cached = true;
+ return callback(null,r);
+ }
+ }
+ }
+ } catch (e) {}
+ }
+
+ geo(ip,function(err,result) {
+ if (err)
+ return callback(err,null);
+ if ((!result)||(!result.location))
+ return callback(new Error('null result'),null);
+
+ cache.put(ip,JSON.stringify({
+ ts: Date.now(),
+ r: result
+ }),function(err) {
+ if (err)
+ console.error('Error saving to cache: '+err);
+ return callback(null,result);
+ });
+ });
+ });
+};
+
+var linebuf = '';
+process.stdin.on('readable',function() {
+ var chunk;
+ while (null !== (chunk = process.stdin.read())) {
+ for(var i=0;i<chunk.length;++i) {
+ let c = chunk[i];
+ if ((c == 0x0d)||(c == 0x0a)) {
+ if (linebuf.length > 0) {
+ let ip = linebuf;
+ lookup(ip,function(err,result) {
+ if ((err)||(!result)||(!result.location)) {
+ return process.stdout.write(ip+',0,0,0,0,0,0\n');
+ } else {
+ let lat = parseFloat(result.location.latitude);
+ let lon = parseFloat(result.location.longitude);
+
+ // Convert to X,Y,Z coordinates from Earth's origin, Earth-as-sphere approximation.
+ let latRadians = lat * 0.01745329251994; // PI / 180
+ let lonRadians = lon * 0.01745329251994; // PI / 180
+ let cosLat = Math.cos(latRadians);
+ let x = Math.round((-6371.0) * cosLat * Math.cos(lonRadians)); // 6371 == Earth's approximate radius in kilometers
+ let y = Math.round(6371.0 * Math.sin(latRadians));
+ let z = Math.round(6371.0 * cosLat * Math.sin(lonRadians));
+
+ return process.stdout.write(ip+',1,'+lat+','+lon+','+x+','+y+','+z+'\n');
+ }
+ });
+ }
+ linebuf = '';
+ } else {
+ linebuf += String.fromCharCode(c);
+ }
+ }
+ }
+});
+
+process.stdin.on('end',function() {
+ cache.close();
+ process.exit(0);
+});
diff --git a/cluster-geo/cluster-geo/config.js.sample b/cluster-geo/cluster-geo/config.js.sample
new file mode 100644
index 00000000..ec1ebfea
--- /dev/null
+++ b/cluster-geo/cluster-geo/config.js.sample
@@ -0,0 +1,7 @@
+// MaxMind GeoIP2 config
+module.exports.maxmind = {
+ userId: 1234,
+ licenseKey: 'asdf',
+ service: 'city',
+ requestTimeout: 1000
+};
diff --git a/cluster-geo/cluster-geo/package.json b/cluster-geo/cluster-geo/package.json
new file mode 100644
index 00000000..53fbc5f4
--- /dev/null
+++ b/cluster-geo/cluster-geo/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "cluster-geo",
+ "version": "1.0.0",
+ "description": "Cluster GEO-IP Query Service",
+ "main": "cluster-geo.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "ZeroTier, Inc.",
+ "license": "GPL-3.0",
+ "dependencies": {
+ "geoip2ws": "^1.7.1",
+ "leveldown": "^1.4.2",
+ "levelup": "^1.3.0"
+ }
+}
diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp
index 334ccc75..049db04e 100644
--- a/controller/SqliteNetworkController.cpp
+++ b/controller/SqliteNetworkController.cpp
@@ -71,6 +71,9 @@
// than this (ms).
#define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
+// Delay between backups in milliseconds
+#define ZT_NETCONF_BACKUP_PERIOD 60000
+
namespace ZeroTier {
namespace {
@@ -122,6 +125,7 @@ struct NetworkRecord {
SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,const char *circuitTestPath) :
_node(node),
+ _backupThreadRun(true),
_dbPath(dbPath),
_circuitTestPath(circuitTestPath),
_db((sqlite3 *)0)
@@ -247,10 +251,15 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
throw std::runtime_error("SqliteNetworkController unable to read instanceId (it's NULL)");
_instanceId = iid;
}
+
+ _backupThread = Thread::start(this);
}
SqliteNetworkController::~SqliteNetworkController()
{
+ _backupThreadRun = false;
+ Thread::join(_backupThread);
+
Mutex::Lock _l(_lock);
if (_db) {
sqlite3_finalize(_sGetNetworkById);
@@ -258,8 +267,6 @@ SqliteNetworkController::~SqliteNetworkController()
sqlite3_finalize(_sCreateMember);
sqlite3_finalize(_sGetNodeIdentity);
sqlite3_finalize(_sCreateOrReplaceNode);
- sqlite3_finalize(_sUpdateNode);
- sqlite3_finalize(_sUpdateNode2);
sqlite3_finalize(_sGetEtherTypesFromRuleTable);
sqlite3_finalize(_sGetActiveBridges);
sqlite3_finalize(_sGetIpAssignmentsForNode);
@@ -505,6 +512,53 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
}
return _doCPGet(path,urlArgs,headers,body,responseBody,responseContentType);
+ } else if ((path.size() == 3)&&(path[2] == "test")) {
+ ZT_CircuitTest *test = (ZT_CircuitTest *)malloc(sizeof(ZT_CircuitTest));
+ memset(test,0,sizeof(ZT_CircuitTest));
+
+ Utils::getSecureRandom(&(test->testId),sizeof(test->testId));
+ test->credentialNetworkId = nwid;
+ test->ptr = (void *)this;
+
+ json_value *j = json_parse(body.c_str(),body.length());
+ if (j) {
+ if (j->type == json_object) {
+ for(unsigned int k=0;k<j->u.object.length;++k) {
+
+ if (!strcmp(j->u.object.values[k].name,"hops")) {
+ if (j->u.object.values[k].value->type == json_array) {
+ for(unsigned int kk=0;kk<j->u.object.values[k].value->u.array.length;++kk) {
+ json_value *hop = j->u.object.values[k].value->u.array.values[kk];
+ if (hop->type == json_array) {
+ for(unsigned int kkk=0;kkk<hop->u.array.length;++kkk) {
+ if (hop->u.array.values[kkk]->type == json_string) {
+ test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(hop->u.array.values[kkk]->u.string.ptr) & 0xffffffffffULL;
+ }
+ }
+ ++test->hopCount;
+ }
+ }
+ }
+ } else if (!strcmp(j->u.object.values[k].name,"reportAtEveryHop")) {
+ if (j->u.object.values[k].value->type == json_boolean)
+ test->reportAtEveryHop = (j->u.object.values[k].value->u.boolean == 0) ? 0 : 1;
+ }
+
+ }
+ }
+ json_value_free(j);
+ }
+
+ if (!test->hopCount) {
+ ::free((void *)test);
+ return 500;
+ }
+
+ test->timestamp = OSUtils::now();
+ _circuitTests[test->testId] = test;
+ _node->circuitTestBegin(test,&(SqliteNetworkController::_circuitTestCallback));
+
+ return 200;
} // else 404
} else {
@@ -946,6 +1000,59 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE(
return 404;
}
+void SqliteNetworkController::threadMain()
+ throw()
+{
+ uint64_t lastBackupTime = 0;
+ while (_backupThreadRun) {
+ if ((OSUtils::now() - lastBackupTime) >= ZT_NETCONF_BACKUP_PERIOD) {
+ lastBackupTime = OSUtils::now();
+
+ char backupPath[4096],backupPath2[4096];
+ Utils::snprintf(backupPath,sizeof(backupPath),"%s.backupInProgress",_dbPath.c_str());
+ Utils::snprintf(backupPath2,sizeof(backupPath),"%s.backup",_dbPath.c_str());
+ OSUtils::rm(backupPath); // delete any unfinished backups
+
+ sqlite3 *bakdb = (sqlite3 *)0;
+ sqlite3_backup *bak = (sqlite3_backup *)0;
+ if (sqlite3_open_v2(backupPath,&bakdb,SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,(const char *)0) != SQLITE_OK) {
+ fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_open_v2()"ZT_EOL_S);
+ continue;
+ }
+ bak = sqlite3_backup_init(bakdb,"main",_db,"main");
+ if (!bak) {
+ sqlite3_close(bakdb);
+ OSUtils::rm(backupPath); // delete any unfinished backups
+ fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_backup_init()"ZT_EOL_S);
+ continue;
+ }
+
+ int rc = SQLITE_OK;
+ for(;;) {
+ if (!_backupThreadRun) {
+ sqlite3_backup_finish(bak);
+ sqlite3_close(bakdb);
+ OSUtils::rm(backupPath);
+ return;
+ }
+ _lock.lock();
+ rc = sqlite3_backup_step(bak,64);
+ _lock.unlock();
+ if ((rc == SQLITE_OK)||(rc == SQLITE_LOCKED)||(rc == SQLITE_BUSY))
+ Thread::sleep(50);
+ else break;
+ }
+
+ sqlite3_backup_finish(bak);
+ sqlite3_close(bakdb);
+
+ OSUtils::rm(backupPath2);
+ ::rename(backupPath,backupPath2);
+ }
+ Thread::sleep(250);
+ }
+}
+
unsigned int SqliteNetworkController::_doCPGet(
const std::vector<std::string> &path,
const std::map<std::string,std::string> &urlArgs,
@@ -1819,4 +1926,75 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c
return NetworkController::NETCONF_QUERY_OK;
}
+void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report)
+{
+ static Mutex circuitTestWriteLock;
+
+ const uint64_t now = OSUtils::now();
+
+ SqliteNetworkController *const c = reinterpret_cast<SqliteNetworkController *>(test->ptr);
+ char tmp[128];
+
+ std::string reportSavePath(c->_circuitTestPath);
+ OSUtils::mkdir(reportSavePath);
+ Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx",test->credentialNetworkId);
+ reportSavePath.append(tmp);
+ OSUtils::mkdir(reportSavePath);
+ Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx_%.16llx",test->timestamp,test->testId);
+ reportSavePath.append(tmp);
+ OSUtils::mkdir(reportSavePath);
+ Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx_%.10llx_%.10llx",now,report->upstream,report->current);
+ reportSavePath.append(tmp);
+
+ {
+ Mutex::Lock _l(circuitTestWriteLock);
+ FILE *f = fopen(reportSavePath.c_str(),"a");
+ if (!f)
+ return;
+ fseek(f,0,SEEK_END);
+ fprintf(f,"%s{\n"
+ "\t\"timestamp\": %llu,"ZT_EOL_S
+ "\t\"testId\": \"%.16llx\","ZT_EOL_S
+ "\t\"upstream\": \"%.10llx\","ZT_EOL_S
+ "\t\"current\": \"%.10llx\","ZT_EOL_S
+ "\t\"receivedTimestamp\": %llu,"ZT_EOL_S
+ "\t\"remoteTimestamp\": %llu,"ZT_EOL_S
+ "\t\"sourcePacketId\": \"%.16llx\","ZT_EOL_S
+ "\t\"flags\": %llu,"ZT_EOL_S
+ "\t\"sourcePacketHopCount\": %u,"ZT_EOL_S
+ "\t\"errorCode\": %u,"ZT_EOL_S
+ "\t\"vendor\": %d,"ZT_EOL_S
+ "\t\"protocolVersion\": %u,"ZT_EOL_S
+ "\t\"majorVersion\": %u,"ZT_EOL_S
+ "\t\"minorVersion\": %u,"ZT_EOL_S
+ "\t\"revision\": %u,"ZT_EOL_S
+ "\t\"platform\": %d,"ZT_EOL_S
+ "\t\"architecture\": %d,"ZT_EOL_S
+ "\t\"receivedOnLocalAddress\": \"%s\","ZT_EOL_S
+ "\t\"receivedFromRemoteAddress\": \"%s\""ZT_EOL_S
+ "}",
+ ((ftell(f) > 0) ? ",\n" : ""),
+ (unsigned long long)report->timestamp,
+ (unsigned long long)test->testId,
+ (unsigned long long)report->upstream,
+ (unsigned long long)report->current,
+ (unsigned long long)now,
+ (unsigned long long)report->remoteTimestamp,
+ (unsigned long long)report->sourcePacketId,
+ (unsigned long long)report->flags,
+ report->sourcePacketHopCount,
+ report->errorCode,
+ (int)report->vendor,
+ report->protocolVersion,
+ report->majorVersion,
+ report->minorVersion,
+ report->revision,
+ (int)report->platform,
+ (int)report->architecture,
+ reinterpret_cast<const InetAddress *>(&(report->receivedOnLocalAddress))->toString().c_str(),
+ reinterpret_cast<const InetAddress *>(&(report->receivedFromRemoteAddress))->toString().c_str());
+ fclose(f);
+ }
+}
+
} // namespace ZeroTier
diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp
index 68529e39..0e2bb63e 100644
--- a/controller/SqliteNetworkController.hpp
+++ b/controller/SqliteNetworkController.hpp
@@ -39,10 +39,14 @@
#include "../node/Constants.hpp"
#include "../node/NetworkController.hpp"
#include "../node/Mutex.hpp"
+#include "../osdep/Thread.hpp"
// Number of in-memory last log entries to maintain per user
#define ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE 32
+// How long do circuit tests "live"? This is just to prevent buildup in memory.
+#define ZT_SQLITENETWORKCONTROLLER_CIRCUIT_TEST_TIMEOUT 300000
+
namespace ZeroTier {
class Node;
@@ -83,6 +87,10 @@ public:
std::string &responseBody,
std::string &responseContentType);
+ // threadMain() for backup thread -- do not call directly
+ void threadMain()
+ throw();
+
private:
enum IpAssignmentType {
// IP assignment is a static IP address
@@ -106,7 +114,11 @@ private:
const Dictionary &metaData,
Dictionary &netconf);
+ static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report);
+
Node *_node;
+ Thread _backupThread;
+ volatile bool _backupThreadRun;
std::string _dbPath;
std::string _circuitTestPath;
std::string _instanceId;
@@ -140,6 +152,9 @@ private:
// Last log entries by address and network ID pair
std::map< std::pair<Address,uint64_t>,_LLEntry > _lastLog;
+ // Circuit tests outstanding
+ std::map< uint64_t,ZT_CircuitTest * > _circuitTests;
+
sqlite3 *_db;
sqlite3_stmt *_sGetNetworkById;
@@ -147,8 +162,6 @@ private:
sqlite3_stmt *_sCreateMember;
sqlite3_stmt *_sGetNodeIdentity;
sqlite3_stmt *_sCreateOrReplaceNode;
- sqlite3_stmt *_sUpdateNode;
- sqlite3_stmt *_sUpdateNode2;
sqlite3_stmt *_sGetEtherTypesFromRuleTable;
sqlite3_stmt *_sGetActiveBridges;
sqlite3_stmt *_sGetIpAssignmentsForNode;
diff --git a/examples/api/README.md b/examples/api/README.md
new file mode 100644
index 00000000..50b1b65e
--- /dev/null
+++ b/examples/api/README.md
@@ -0,0 +1,26 @@
+API Examples
+======
+
+This folder contains examples that can be posted with curl or another http query utility to a local instance.
+
+To test querying with curl:
+
+ curl -H 'X-ZT1-Auth:AUTHTOKEN' http://127.0.0.1:9993/status
+
+To create a public network on a local controller (service must be built with "make ZT\_ENABLE\_NETWORK\_CONTROLLER=1"):
+
+ curl -H 'X-ZT1-Auth:AUTHTOKEN' -X POST -d @public.json http://127.0.0.1:9993/controller/network/################
+
+Replace AUTHTOKEN with the contents of this instance's authtoken.secret file and ################ with a valid network ID. Its first 10 hex digits must be the ZeroTier address of the controller itself, while the last 6 hex digits can be anything. Also be sure to change the port if you have this instance listening somewhere other than 9993.
+
+After POSTing you can double check the network config with:
+
+ curl -H 'X-ZT1-Auth:AUTHTOKEN' http://127.0.0.1:9993/controller/network/################
+
+Once this network is created (and if your controller is online, etc.) you can then join this network from any device anywhere in the world and it will receive a valid network configuration.
+
+---
+
+**public.json**: A valid configuration for a public network that allows IPv4 and IPv6 traffic.
+
+**circuit-test-pingpong.json**: An example circuit test that can be posted to /controller/network/################/test to order a test -- you will have to edit this to insert the hops you want since the two hard coded device IDs are from our own test instances.
diff --git a/examples/api/circuit-test-pingpong.json b/examples/api/circuit-test-pingpong.json
new file mode 100644
index 00000000..8fcc5d94
--- /dev/null
+++ b/examples/api/circuit-test-pingpong.json
@@ -0,0 +1,13 @@
+{
+ "hops": [
+ [ "4cbc810d4c" ],
+ [ "868cd1664f" ],
+ [ "4cbc810d4c" ],
+ [ "868cd1664f" ],
+ [ "4cbc810d4c" ],
+ [ "868cd1664f" ],
+ [ "4cbc810d4c" ],
+ [ "868cd1664f" ]
+ ],
+ "reportAtEveryHop": true
+}
diff --git a/examples/api/public.json b/examples/api/public.json
new file mode 100644
index 00000000..4317bd3e
--- /dev/null
+++ b/examples/api/public.json
@@ -0,0 +1,27 @@
+{
+ "name": "public_test_network",
+ "private": false,
+ "enableBroadcast": true,
+ "allowPassiveBridging": false,
+ "v4AssignMode": "zt",
+ "v6AssignMode": "rfc4193",
+ "multicastLimit": 32,
+ "relays": [],
+ "gateways": [],
+ "ipLocalRoutes": ["10.66.0.0/16"],
+ "ipAssignmentPools": [{"ipRangeStart":"10.66.0.1","ipRangeEnd":"10.66.255.254"}],
+ "rules": [
+ {
+ "ruleNo": 10,
+ "etherType": 2048,
+ "action": "accept"
+ },{
+ "ruleNo": 20,
+ "etherType": 2054,
+ "action": "accept"
+ },{
+ "ruleNo": 30,
+ "etherType": 34525,
+ "action": "accept"
+ }]
+}
diff --git a/examples/docker/Dockerfile b/examples/docker/Dockerfile
new file mode 100644
index 00000000..f1ce6bb5
--- /dev/null
+++ b/examples/docker/Dockerfile
@@ -0,0 +1,19 @@
+FROM centos:7
+
+MAINTAINER https://www.zerotier.com/
+
+RUN yum -y update && yum install -y sqlite net-tools && yum clean all
+
+EXPOSE 9993/udp
+
+RUN mkdir -p /var/lib/zerotier-one
+RUN mkdir -p /var/lib/zerotier-one/networks.d
+RUN ln -sf /var/lib/zerotier-one/zerotier-one /usr/local/bin/zerotier-cli
+RUN ln -sf /var/lib/zerotier-one/zerotier-one /usr/local/bin/zerotier-idtool
+
+ADD zerotier-one /var/lib/zerotier-one/
+
+ADD main.sh /
+RUN chmod a+x /main.sh
+
+CMD ["./main.sh"]
diff --git a/examples/docker/README.md b/examples/docker/README.md
new file mode 100644
index 00000000..fbc93481
--- /dev/null
+++ b/examples/docker/README.md
@@ -0,0 +1,8 @@
+Simple Dockerfile Example
+======
+
+This is a simple Docker example using ZeroTier One in normal tun/tap mode. It uses a Dockerfile to build an image containing ZeroTier One and a main.sh that launches it with an identity supplied via the Docker environment via the ZEROTIER\_IDENTITY\_SECRET and ZEROTIER\_NETWORK variables. The Dockerfile assumes that the zerotier-one binary is in the build folder.
+
+This is not a very secure way to load an identity secret, but it's useful for testing since it allows you to repeatedly launch Docker containers with the same identity. For production we'd recommend using something like Hashicorp Vault, or modifying main.sh to leave identities unspecified and allow the container to generate a new identity at runtime. Then you could script approval of containers using the controller API, approving them as they launch, etc. (We are working on better ways of doing mass provisioning.)
+
+To use in normal tun/tap mode with Docker, containers must be run with the options "--device=/dev/net/tun --privileged". The main.sh script supplied here will complain and exit if these options are not present (no /dev/net/tun device).
diff --git a/examples/docker/main.sh b/examples/docker/main.sh
new file mode 100644
index 00000000..53fb6540
--- /dev/null
+++ b/examples/docker/main.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin
+
+if [ ! -c "/dev/net/tun" ]; then
+ echo 'FATAL: must be docker run with: --device=/dev/net/tun --cap-add=NET_ADMIN'
+ exit 1
+fi
+
+if [ -z "$ZEROTIER_IDENTITY_SECRET" ]; then
+ echo 'FATAL: ZEROTIER_IDENTITY_SECRET not set -- aborting!'
+ exit 1
+fi
+
+if [ -z "$ZEROTIER_NETWORK" ]; then
+ echo 'Warning: ZEROTIER_NETWORK not set, you will need to docker exec zerotier-cli to join a network.'
+else
+ # The existence of a .conf will cause the service to "remember" this network
+ touch /var/lib/zerotier-one/networks.d/$ZEROTIER_NETWORK.conf
+fi
+
+rm -f /var/lib/zerotier-one/identity.*
+echo "$ZEROTIER_IDENTITY_SECRET" >/var/lib/zerotier-one/identity.secret
+
+/var/lib/zerotier-one/zerotier-one
diff --git a/examples/docker/maketestenv.sh b/examples/docker/maketestenv.sh
new file mode 100755
index 00000000..275692e1
--- /dev/null
+++ b/examples/docker/maketestenv.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ -z "$1" -o -z "$2" ]; then
+ echo 'Usage: maketestenv.sh <output file e.g. test-01.env> <network ID>'
+ exit 1
+fi
+
+newid=`../../zerotier-idtool generate`
+
+echo "ZEROTIER_IDENTITY_SECRET=$newid" >$1
+echo "ZEROTIER_NETWORK=$2" >>$1
diff --git a/ext/bin/miniupnpc/README.md b/ext/bin/miniupnpc/README.md
deleted file mode 100644
index c3d538ba..00000000
--- a/ext/bin/miniupnpc/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-libminiupnpc binaries
-======
-
-This is a binary build of [libminiupnpc](http://miniupnp.free.fr) for certain architectures to faciliate easy building. Where possible the build flags were set for improved security by enabling options like stack protector (a.k.a. stack canary), ASLR support, etc.
diff --git a/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h b/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h
deleted file mode 100644
index 915b0026..00000000
--- a/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
-/* Project: miniupnp
- * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
- * Author: Thomas Bernard
- * Copyright (c) 2005-2007 Thomas Bernard
- * This software is subjects to the conditions detailed
- * in the LICENCE file provided within this distribution */
-#ifndef MINISSDPC_H_INCLUDED
-#define MINISSDPC_H_INCLUDED
-
-struct UPNPDev *
-getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath);
-
-#endif
-
diff --git a/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a b/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a
deleted file mode 100644
index 4983f628..00000000
--- a/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a
+++ /dev/null
Binary files differ
diff --git a/ext/bin/miniupnpc/linux-x64/libminiupnpc.a b/ext/bin/miniupnpc/linux-x64/libminiupnpc.a
deleted file mode 100644
index 270366e0..00000000
--- a/ext/bin/miniupnpc/linux-x64/libminiupnpc.a
+++ /dev/null
Binary files differ
diff --git a/ext/bin/miniupnpc/linux-x86/libminiupnpc.a b/ext/bin/miniupnpc/linux-x86/libminiupnpc.a
deleted file mode 100644
index 99cbef21..00000000
--- a/ext/bin/miniupnpc/linux-x86/libminiupnpc.a
+++ /dev/null
Binary files differ
diff --git a/ext/bin/miniupnpc/mac-x64/libminiupnpc.a b/ext/bin/miniupnpc/mac-x64/libminiupnpc.a
deleted file mode 100644
index 3c2e528d..00000000
--- a/ext/bin/miniupnpc/mac-x64/libminiupnpc.a
+++ /dev/null
Binary files differ
diff --git a/ext/bin/miniupnpc/windows-x64/miniupnpc.lib b/ext/bin/miniupnpc/windows-x64/miniupnpc.lib
deleted file mode 100644
index e05fefc8..00000000
--- a/ext/bin/miniupnpc/windows-x64/miniupnpc.lib
+++ /dev/null
Binary files differ
diff --git a/ext/bin/miniupnpc/windows-x86/miniupnpc.lib b/ext/bin/miniupnpc/windows-x86/miniupnpc.lib
deleted file mode 100644
index a7fe4191..00000000
--- a/ext/bin/miniupnpc/windows-x86/miniupnpc.lib
+++ /dev/null
Binary files differ
diff --git a/ext/bin/tap-mac/tap.kext.old/Contents/Info.plist b/ext/bin/tap-mac/tap.kext.old/Contents/Info.plist
new file mode 100644
index 00000000..45c2839a
--- /dev/null
+++ b/ext/bin/tap-mac/tap.kext.old/Contents/Info.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>tap</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.zerotier.tap</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>tap</string>
+ <key>CFBundlePackageType</key>
+ <string>KEXT</string>
+ <key>CFBundleShortVersionString</key>
+ <string>20131028</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.mach</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.bsd</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.libkern</key>
+ <string>8.0</string>
+ <key>com.apple.kpi.unsupported</key>
+ <string>8.0</string>
+ </dict>
+</dict>
+</plist>
+
diff --git a/ext/bin/tap-mac/tap.kext.old/Contents/MacOS/tap b/ext/bin/tap-mac/tap.kext.old/Contents/MacOS/tap
new file mode 100755
index 00000000..6a9021a7
--- /dev/null
+++ b/ext/bin/tap-mac/tap.kext.old/Contents/MacOS/tap
Binary files differ
diff --git a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeDirectory b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeDirectory
index 58c421c2..58c421c2 100644
--- a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeDirectory
+++ b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeDirectory
Binary files differ
diff --git a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeRequirements b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeRequirements
index 1df93129..1df93129 100644
--- a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeRequirements
+++ b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeRequirements
Binary files differ
diff --git a/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeResources b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeResources
new file mode 100644
index 00000000..0710b400
--- /dev/null
+++ b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeResources
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>files</key>
+ <dict/>
+ <key>files2</key>
+ <dict/>
+ <key>rules</key>
+ <dict>
+ <key>^Resources/</key>
+ <true/>
+ <key>^Resources/.*\.lproj/</key>
+ <dict>
+ <key>optional</key>
+ <true/>
+ <key>weight</key>
+ <real>1000</real>
+ </dict>
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>1100</real>
+ </dict>
+ <key>^version.plist$</key>
+ <true/>
+ </dict>
+ <key>rules2</key>
+ <dict>
+ <key>.*\.dSYM($|/)</key>
+ <dict>
+ <key>weight</key>
+ <real>11</real>
+ </dict>
+ <key>^(.*/)?\.DS_Store$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>2000</real>
+ </dict>
+ <key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
+ <dict>
+ <key>nested</key>
+ <true/>
+ <key>weight</key>
+ <real>10</real>
+ </dict>
+ <key>^.*</key>
+ <true/>
+ <key>^Info\.plist$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ <key>^PkgInfo$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ <key>^Resources/</key>
+ <dict>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ <key>^Resources/.*\.lproj/</key>
+ <dict>
+ <key>optional</key>
+ <true/>
+ <key>weight</key>
+ <real>1000</real>
+ </dict>
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>1100</real>
+ </dict>
+ <key>^[^/]+$</key>
+ <dict>
+ <key>nested</key>
+ <true/>
+ <key>weight</key>
+ <real>10</real>
+ </dict>
+ <key>^embedded\.provisionprofile$</key>
+ <dict>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ <key>^version\.plist$</key>
+ <dict>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeSignature b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeSignature
index 64429727..64429727 100644
--- a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeSignature
+++ b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeSignature
Binary files differ
diff --git a/ext/bin/tap-mac/tap.kext/Contents/Info.plist b/ext/bin/tap-mac/tap.kext/Contents/Info.plist
index 45c2839a..c20eefa5 100644
--- a/ext/bin/tap-mac/tap.kext/Contents/Info.plist
+++ b/ext/bin/tap-mac/tap.kext/Contents/Info.plist
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleShortVersionString</key>
- <string>20131028</string>
+ <string>20150118</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
diff --git a/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap b/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap
index 6a9021a7..48bf9625 100755
--- a/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap
+++ b/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap
Binary files differ
diff --git a/ext/installfiles/linux/buildinstaller.sh b/ext/installfiles/linux/buildinstaller.sh
index 4f661b8d..1f6f8935 100755
--- a/ext/installfiles/linux/buildinstaller.sh
+++ b/ext/installfiles/linux/buildinstaller.sh
@@ -41,7 +41,7 @@ case "$system" in
machine="x64"
debian_arch="amd64"
;;
- armv6l|arm|armhf)
+ armv6l|arm|armhf|arm7l|armv7l)
machine="armv6l"
debian_arch="armhf"
;;
diff --git a/ext/installfiles/mac/launch.sh b/ext/installfiles/mac/launch.sh
index ef22ccbd..41c4b9c8 100755
--- a/ext/installfiles/mac/launch.sh
+++ b/ext/installfiles/mac/launch.sh
@@ -1,15 +1,7 @@
#!/bin/bash
zthome="/Library/Application Support/ZeroTier/One"
-export PATH="/bin:/usr/bin:/sbin:/usr/sbin:$zthome"
-
-# If the app has been deleted, uninstall the service
-cd "$zthome"
-if [ -L './shutdownIfUnreadable' -a ! -f "`readlink ./shutdownIfUnreadable`" ]; then
- rm -f /tmp/ZeroTierOneUninstall.log
- /bin/bash "$zthome/uninstall.sh" >/tmp/ZeroTierOneUninstall.log 2>&1
- exit 0
-fi
+export PATH="$zthome:/bin:/usr/bin:/sbin:/usr/sbin"
# Launch ZeroTier One (not as daemon... launchd monitors it)
exec zerotier-one
diff --git a/ext/installfiles/mac/postinst.sh b/ext/installfiles/mac/postinst.sh
index 7d3d516f..da15f9c8 100755
--- a/ext/installfiles/mac/postinst.sh
+++ b/ext/installfiles/mac/postinst.sh
@@ -1,22 +1,42 @@
#!/bin/bash
-export PATH=/bin:/usr/bin:/sbin:/usr/sbin
+export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin
+
+OSX_RELEASE=`sw_vers -productVersion | cut -d . -f 1,2`
launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1
+sleep 1
cd "/Library/Application Support/ZeroTier/One"
+
+if [ "$OSX_RELEASE" = "10.7" ]; then
+ # OSX 10.7 cannot use the new tap driver since the new way of kext signing
+ # is not backward compatible. Pull the old one for 10.7 users and replace.
+ # We use https to fetch and check hash as an extra added measure.
+ rm -f tap.kext.10_7.tar.gz
+ curl -s https://download.zerotier.com/tap.kext.10_7.tar.gz >tap.kext.10_7.tar.gz
+ if [ -s tap.kext.10_7.tar.gz -a "`shasum -a 256 tap.kext.10_7.tar.gz | cut -d ' ' -f 1`" = "e133d4832cef571621d3618f417381b44f51a76ed625089fb4e545e65d3ef2a9" ]; then
+ rm -rf tap.kext
+ tar -xzf tap.kext.10_7.tar.gz
+ fi
+ rm -f tap.kext.10_7.tar.gz
+fi
+
rm -rf node.log node.log.old root-topology shutdownIfUnreadable autoupdate.log updates.d
+chown -R 0 tap.kext
+chgrp -R 0 tap.kext
if [ ! -f authtoken.secret ]; then
head -c 4096 /dev/urandom | md5 | head -c 24 >authtoken.secret
- chown root authtoken.secret
- chgrp wheel authtoken.secret
+ chown 0 authtoken.secret
+ chgrp 0 authtoken.secret
chmod 0600 authtoken.secret
fi
rm -f zerotier-cli zerotier-idtool
ln -sf zerotier-one zerotier-cli
ln -sf zerotier-one zerotier-idtool
-cd /usr/bin
+mkdir -p /usr/local/bin
+cd /usr/local/bin
rm -f zerotier-cli zerotier-idtool
ln -sf "/Library/Application Support/ZeroTier/One/zerotier-one" zerotier-cli
ln -sf "/Library/Application Support/ZeroTier/One/zerotier-one" zerotier-idtool
diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip
index 236e2559..147094f9 100644
--- a/ext/installfiles/windows/ZeroTier One.aip
+++ b/ext/installfiles/windows/ZeroTier One.aip
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<DOCUMENT Type="Advanced Installer" CreateVersion="10.9" version="12.3.1" Modules="enterprise" RootPath="." Language="en" Id="{DC564647-6BF0-4550-87F4-89C938D0159C}">
+<DOCUMENT Type="Advanced Installer" CreateVersion="10.9" version="12.5" Modules="enterprise" RootPath="." Language="en" Id="{DC564647-6BF0-4550-87F4-89C938D0159C}">
<COMPONENT cid="caphyon.advinst.msicomp.ProjectOptionsComponent">
<ROW Name="HiddenItems" Value="UpdaterComponent;SerValComponent;AutorunComponent;MultipleInstancesComponent;MsiJavaComponent;MsiRegsComponent;MsiExtComponent;MsiAssemblyComponent;MsiDriverPackagesComponent;AnalyticsComponent;ActSyncAppComponent;MsiMergeModsComponent;MsiThemeComponent;BackgroundImagesComponent;DictionaryComponent;MsiEnvComponent;ScheduledTasksComponent;CPLAppletComponent;GameUxComponent;UserAccountsComponent;MsiClassComponent;WebApplicationsComponent;MsiOdbcDataSrcComponent;SqlConnectionComponent;SharePointSlnComponent;SilverlightSlnComponent;MsiAppSearchComponent"/>
</COMPONENT>
@@ -7,7 +7,10 @@
<ROW Property="AI_BITMAP_DISPLAY_MODE" Value="0"/>
<ROW Property="AI_EMBD_MSI_EXTR_PATH" Value="[TempFolder]" ValueLocId="-"/>
<ROW Property="AI_EXTERNALUIUNINSTALLERNAME" MultiBuildValue="DefaultBuild:aiui"/>
+ <ROW Property="AI_PREDEF_LCONDS_PROPS" Value="AI_DETECTED_DOTNET_VERSION"/>
<ROW Property="AI_PRODUCTNAME_ARP" Value="ZeroTier One"/>
+ <ROW Property="AI_REQUIRED_DOTNET_DISPLAY" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/>
+ <ROW Property="AI_REQUIRED_DOTNET_VERSION" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/>
<ROW Property="AI_UNINSTALLER" Value="msiexec.exe"/>
<ROW Property="ALLUSERS" Value="1"/>
<ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]."/>
@@ -23,10 +26,10 @@
<ROW Property="CTRLS" Value="2"/>
<ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/>
<ROW Property="Manufacturer" Value="ZeroTier, Inc."/>
- <ROW Property="ProductCode" Value="1033:{BBE07631-7B85-4531-A601-B7BAD339AF4D} " Type="16"/>
+ <ROW Property="ProductCode" Value="1033:{E517BA79-1770-4556-B7A4-622434A9982B} " Type="16"/>
<ROW Property="ProductLanguage" Value="1033"/>
<ROW Property="ProductName" Value="ZeroTier One"/>
- <ROW Property="ProductVersion" Value="1.0.4" Type="32"/>
+ <ROW Property="ProductVersion" Value="1.1.0" Type="32"/>
<ROW Property="REBOOT" MultiBuildValue="DefaultBuild:ReallySuppress"/>
<ROW Property="RUNAPPLICATION" Value="1" Type="4"/>
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>
@@ -41,7 +44,7 @@
<ROW Property="WindowsTypeNTDisplay" MultiBuildValue="DefaultBuild:Windows 2000, Windows XP x86, Windows Server 2003 x86" ValueLocId="-"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">
- <ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1" DirectoryOptions="3"/>
+ <ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1" DirectoryOptions="2"/>
<ROW Directory="CommonAppDataFolder" Directory_Parent="TARGETDIR" DefaultDir="COMMON~1|CommonAppDataFolder" IsPseudoRoot="1"/>
<ROW Directory="One_Dir" Directory_Parent="ZeroTier_Dir" DefaultDir="One"/>
<ROW Directory="ProgramFilesFolder" Directory_Parent="TARGETDIR" DefaultDir="PROGRA~1|ProgramFilesFolder" IsPseudoRoot="1"/>
@@ -56,8 +59,9 @@
<ROW Directory="x86_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x86"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
- <ROW Component="AI_CustomARPName" ComponentId="{BCC96839-1488-49BC-97C4-92E710FB511C}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
+ <ROW Component="AI_CustomARPName" ComponentId="{CD637A90-1485-4337-ABA6-C58C97157356}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
<ROW Component="AI_DisableModify" ComponentId="{020DCABD-5D56-49B9-AF48-F07F0B55E590}" Directory_="APPDIR" Attributes="4" KeyPath="NoModify" Options="1"/>
+ <ROW Component="Newtonsoft.Json.dll" ComponentId="{0B2F229D-5425-42FB-9E28-F6D25AB2B4B5}" Directory_="APPDIR" Attributes="0" KeyPath="Newtonsoft.Json.dll"/>
<ROW Component="ProductInformation" ComponentId="{DB078D04-EA8E-4A7C-9001-89BAD932F9D9}" Directory_="APPDIR" Attributes="4" KeyPath="Version"/>
<ROW Component="ZeroTierOne.exe" ComponentId="{18B51525-77BF-4FD9-9C18-A10D4CFC25BA}" Directory_="APPDIR" Attributes="0" KeyPath="ZeroTierOne.exe"/>
<ROW Component="index.html" ComponentId="{24AB46DC-56EA-4F3C-A8B7-95957509CDD1}" Directory_="ui_Dir" Attributes="0" KeyPath="index.html" Type="0"/>
@@ -69,11 +73,12 @@
<ROW Component="zttap300.cat_1" ComponentId="{9F913E48-095B-4EA3-98DA-EDAB1593F3E3}" Directory_="x86_Dir" Attributes="0" Condition="NOT VersionNT64" KeyPath="zttap300.cat_3" Type="0"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
- <ROW Feature="ZeroTierOne" Title="MainFeature" Description="ZeroTier One" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="AI_CustomARPName AI_DisableModify ProductInformation ZeroTierOne.exe index.html networks.d regid.201001.com.zerotier zerotierone_x64.exe zerotierone_x86.exe zttap300.cat zttap300.cat_1"/>
+ <ROW Feature="ZeroTierOne" Title="MainFeature" Description="ZeroTier One" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="AI_CustomARPName AI_DisableModify Newtonsoft.Json.dll ProductInformation ZeroTierOne.exe index.html networks.d regid.201001.com.zerotier zerotierone_x64.exe zerotierone_x86.exe zttap300.cat zttap300.cat_1"/>
<ATTRIBUTE name="CurrentFeature" value="ZeroTierOne"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
- <ROW File="ZeroTierOne.exe" Component_="ZeroTierOne.exe" FileName="ZEROTI~1.EXE|ZeroTier One.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\bin\win-ui-wrapper\ZeroTier One.exe" SelfReg="false" NextFile="zttap300.cat_2"/>
+ <ROW File="Newtonsoft.Json.dll" Component_="Newtonsoft.Json.dll" FileName="NEWTON~1.DLL|Newtonsoft.Json.dll" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\windows\WinUI\bin\Release\Newtonsoft.Json.dll" SelfReg="false" DigSign="true"/>
+ <ROW File="ZeroTierOne.exe" Component_="ZeroTierOne.exe" FileName="ZEROTI~1.EXE|ZeroTier One.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\windows\WinUI\bin\Release\ZeroTier One.exe" SelfReg="false" NextFile="zttap300.cat_2" DigSign="true"/>
<ROW File="index.html" Component_="index.html" FileName="INDEX~1.HTM|index.html" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\ui\index.html" SelfReg="false" NextFile="main.js"/>
<ROW File="main.js" Component_="index.html" FileName="main.js" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\ui\main.js" SelfReg="false" NextFile="react.min.js"/>
<ROW File="react.min.js" Component_="index.html" FileName="REACTM~1.JS|react.min.js" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\ui\react.min.js" SelfReg="false" NextFile="simpleajax.min.js"/>
@@ -87,7 +92,7 @@
<ROW File="zttap300.inf_1" Component_="zttap300.cat_1" FileName="zttap300.inf" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.inf" SelfReg="false" NextFile="index.html"/>
<ROW File="zttap300.sys_2" Component_="zttap300.cat" FileName="zttap300.sys" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.sys" SelfReg="false" NextFile="zttap300.inf"/>
<ROW File="zttap300.sys_3" Component_="zttap300.cat_1" FileName="zttap300.sys" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.sys" SelfReg="false" NextFile="zttap300.inf_1"/>
- <ROW File="ztui.min.js" Component_="index.html" FileName="ZTUIMI~1.JS|ztui.min.js" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\ui\ztui.min.js" SelfReg="false"/>
+ <ROW File="ztui.min.js" Component_="index.html" FileName="ZTUIMI~1.JS|ztui.min.js" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\ui\ztui.min.js" SelfReg="false" NextFile="Newtonsoft.Json.dll"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">
<ROW BuildKey="DefaultBuild" BuildName="MSI" BuildOrder="1" BuildType="1" PackageFolder="..\..\.." PackageFileName="ZeroTier One" Languages="en" InstallationType="4" ExtUI="true" UseLargeSchema="true"/>
@@ -144,6 +149,7 @@
<ROW Name="ExternalUICleaner.dll" SourcePath="&lt;AI_CUSTACTS&gt;ExternalUICleaner.dll"/>
<ROW Name="NetFirewall.dll" SourcePath="&lt;AI_CUSTACTS&gt;NetFirewall.dll"/>
<ROW Name="ShortcutFlags.dll" SourcePath="&lt;AI_CUSTACTS&gt;ShortcutFlags.dll"/>
+ <ROW Name="SoftwareDetector.dll" SourcePath="&lt;AI_CUSTACTS&gt;SoftwareDetector.dll"/>
<ROW Name="aicustact.dll" SourcePath="&lt;AI_CUSTACTS&gt;aicustact.dll"/>
<ROW Name="chainersupport.dll" SourcePath="&lt;AI_CUSTACTS&gt;chainersupport.dll"/>
<ROW Name="msichainer.exe" SourcePath="&lt;AI_CUSTACTS&gt;msichainer.exe"/>
@@ -194,6 +200,7 @@
<ROW Action="AI_DATA_SETTER_2" Type="51" Source="CustomActionData" Target="[~]"/>
<ROW Action="AI_DATA_SETTER_3" Type="51" Source="CustomActionData" Target="[~]"/>
<ROW Action="AI_DOWNGRADE" Type="19" Target="4010"/>
+ <ROW Action="AI_DetectSoftware" Type="257" Source="SoftwareDetector.dll" Target="OnDetectSoftware"/>
<ROW Action="AI_DoRemoveExternalUIStub" Type="3585" Source="ExternalUICleaner.dll" Target="DoRemoveExternalUIStub" WithoutSeq="true"/>
<ROW Action="AI_DpiContentScale" Type="1" Source="aicustact.dll" Target="DpiContentScale"/>
<ROW Action="AI_FwConfig" Type="11265" Source="NetFirewall.dll" Target="OnFwConfig" WithoutSeq="true"/>
@@ -243,7 +250,7 @@
<ROW Action="AI_DATA_SETTER" Condition="(REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5101"/>
<ROW Action="AI_XmlUninstall" Condition="(REMOVE)" Sequence="3102"/>
<ROW Action="AI_DATA_SETTER_1" Condition="(REMOVE)" Sequence="3101"/>
- <ROW Action="InstallFinalize" Sequence="6596" SeqType="0" MsiKey="InstallFinalize"/>
+ <ROW Action="InstallFinalize" Sequence="6597" SeqType="0" MsiKey="InstallFinalize"/>
<ROW Action="AI_RemoveExternalUIStub" Condition="(REMOVE=&quot;ALL&quot;) AND ((VersionNT &gt; 500) OR((VersionNT = 500) AND (ServicePackLevel &gt;= 4)))" Sequence="1501"/>
<ROW Action="AI_GetArpIconPath" Sequence="1401"/>
<ROW Action="TapDeviceRemove32" Condition="( Installed AND ( REMOVE = &quot;ALL&quot; OR AI_INSTALL_MODE = &quot;Remove&quot; ) AND NOT UPGRADINGPRODUCTCODE ) AND ( NOT VersionNT64 )" Sequence="1601"/>
@@ -253,19 +260,22 @@
<ROW Action="AI_DATA_SETTER_2" Condition="(VersionNT &gt;= 501) AND (REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5801"/>
<ROW Action="AI_FwUninstall" Condition="(VersionNT &gt;= 501) AND (REMOVE=&quot;ALL&quot;)" Sequence="1702"/>
<ROW Action="AI_DATA_SETTER_3" Condition="(VersionNT &gt;= 501) AND (REMOVE=&quot;ALL&quot;)" Sequence="1701"/>
+ <ROW Action="AI_DetectSoftware" Sequence="101"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent">
<ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="749"/>
<ROW Action="AI_ResolveKnownFolders" Sequence="52"/>
<ROW Action="AI_DpiContentScale" Sequence="51"/>
<ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Sequence="99"/>
- <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Condition="AI_SETUPEXEPATH_ORIGINAL" Sequence="101"/>
+ <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Condition="AI_SETUPEXEPATH_ORIGINAL" Sequence="102"/>
<ROW Action="ExecuteAction" Sequence="1299" SeqType="0" MsiKey="ExecuteAction"/>
+ <ROW Action="AI_DetectSoftware" Sequence="101"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiLaunchConditionsComponent">
<ROW Condition="( Version9X OR ( NOT VersionNT64 ) OR ( VersionNT64 AND ((VersionNT64 &lt;&gt; 502) OR (((VersionNT64 = 502) AND (ServicePackLevel &gt;= 1)) OR (MsiNTProductType &lt;&gt; 1))) AND ((VersionNT64 &lt;&gt; 502) OR (((VersionNT64 = 502) AND (ServicePackLevel &lt;&gt; 1)) OR (MsiNTProductType &lt;&gt; 1))) AND ((VersionNT64 &lt;&gt; 502) OR (((VersionNT64 = 502) AND (ServicePackLevel &lt;&gt; 2)) OR (MsiNTProductType &lt;&gt; 1))) AND ((VersionNT64 &lt;&gt; 502) OR ((VersionNT64 = 502) AND ((MsiNTProductType = 1) OR (ServicePackLevel &gt;= 1)))) AND ((VersionNT64 &lt;&gt; 502) OR ((VersionNT64 = 502) AND ((MsiNTProductType = 1) OR (ServicePackLevel &lt;&gt; 1)))) AND ((VersionNT64 &lt;&gt; 502) OR ((VersionNT64 = 502) AND ((MsiNTProductType = 1) OR (ServicePackLevel &lt;&gt; 2)))) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNT64Display]" DescriptionLocId="AI.LaunchCondition.NoSpecificNT64" IsPredefined="true" Builds="DefaultBuild"/>
<ROW Condition="( Version9X OR VersionNT64 OR ( VersionNT AND ((VersionNT &lt;&gt; 500) OR ((VersionNT = 500) AND (ServicePackLevel &gt;= 1))) AND ((VersionNT &lt;&gt; 500) OR ((VersionNT = 500) AND (ServicePackLevel &lt;&gt; 1))) AND ((VersionNT &lt;&gt; 500) OR ((VersionNT = 500) AND (ServicePackLevel &lt;&gt; 2))) AND ((VersionNT &lt;&gt; 500) OR ((VersionNT = 500) AND (ServicePackLevel &lt;&gt; 3))) AND ((VersionNT &lt;&gt; 500) OR ((VersionNT = 500) AND (ServicePackLevel &lt;&gt; 4))) AND (((VersionNT &lt;&gt; 501) OR ((VersionNT = 501) AND (ServicePackLevel &gt;= 1))) OR VersionNT64) AND (((VersionNT &lt;&gt; 501) OR ((VersionNT = 501) AND (ServicePackLevel &lt;&gt; 1))) OR VersionNT64) AND (((VersionNT &lt;&gt; 501) OR ((VersionNT = 501) AND (ServicePackLevel &lt;&gt; 2))) OR VersionNT64) AND (((VersionNT &lt;&gt; 501) OR ((VersionNT = 501) AND (ServicePackLevel &lt;&gt; 3))) OR VersionNT64) AND (((VersionNT &lt;&gt; 502) OR ((VersionNT = 502) AND (ServicePackLevel &gt;= 1))) OR VersionNT64) AND (((VersionNT &lt;&gt; 502) OR ((VersionNT = 502) AND (ServicePackLevel &lt;&gt; 1))) OR VersionNT64) AND (((VersionNT &lt;&gt; 502) OR ((VersionNT = 502) AND (ServicePackLevel &lt;&gt; 2))) OR VersionNT64) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNTDisplay]" DescriptionLocId="AI.LaunchCondition.NoSpecificNT" IsPredefined="true" Builds="DefaultBuild"/>
<ROW Condition="(VersionNT &lt;&gt; 400)" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNT40Display]" DescriptionLocId="AI.LaunchCondition.NoNT40" IsPredefined="true" Builds="DefaultBuild"/>
+ <ROW Condition="AI_DETECTED_DOTNET_VERSION &gt;= AI_REQUIRED_DOTNET_VERSION" Description="[ProductName] cannot be installed on systems with .NET Framework version lower than [AI_REQUIRED_DOTNET_DISPLAY]." DescriptionLocId="AI.LaunchCondition.DotNET" IsPredefined="true" Builds="DefaultBuild"/>
<ROW Condition="Privileged" Description="[ProductName] requires administrative privileges to install." DescriptionLocId="AI.LaunchCondition.Privileged" IsPredefined="true" Builds="DefaultBuild"/>
<ROW Condition="VersionNT" Description="[ProductName] cannot be installed on [WindowsType9XDisplay]" DescriptionLocId="AI.LaunchCondition.No9X" IsPredefined="true" Builds="DefaultBuild"/>
</COMPONENT>
@@ -328,10 +338,10 @@
<ROW XmlAttribute="xsischemaLocation" XmlElement="swidsoftware_identification_tag" Name="xsi:schemaLocation" Flags="14" Order="3" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.XmlElementComponent">
- <ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="4"/>
+ <ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="0"/>
<ROW XmlElement="swidentitlement_required_indicator" ParentElement="swidsoftware_identification_tag" Name="swid:entitlement_required_indicator" Condition="1" Order="0" Flags="14" Text="false"/>
<ROW XmlElement="swidmajor" ParentElement="swidnumeric" Name="swid:major" Condition="1" Order="0" Flags="14" Text="1"/>
- <ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Condition="1" Order="1" Flags="14" Text="0"/>
+ <ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Condition="1" Order="1" Flags="14" Text="1"/>
<ROW XmlElement="swidname" ParentElement="swidproduct_version" Name="swid:name" Condition="1" Order="0" Flags="14" Text="[ProductVersion]"/>
<ROW XmlElement="swidname_1" ParentElement="swidsoftware_creator" Name="swid:name" Condition="1" Order="0" Flags="14" Text="ZeroTier, Inc."/>
<ROW XmlElement="swidname_2" ParentElement="swidsoftware_licensor" Name="swid:name" Condition="1" Order="0" Flags="14" Text="ZeroTier, Inc."/>
diff --git a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Info.plist b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Info.plist
index a11af6d9..c67923c7 100644
--- a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Info.plist
+++ b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Info.plist
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
- <string>14E46</string>
+ <string>15B42</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
@@ -22,26 +22,35 @@
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
+ <key>CFBundleSupportedPlatforms</key>
+ <array>
+ <string>MacOSX</string>
+ </array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
- <string>6E35b</string>
+ <string>7B1005</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
- <string>14D125</string>
+ <string>15A278</string>
<key>DTSDKName</key>
- <string>macosx10.10</string>
+ <string>macosx10.11</string>
<key>DTXcode</key>
- <string>0640</string>
+ <string>0711</string>
<key>DTXcodeBuild</key>
- <string>6E35b</string>
+ <string>7B1005</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
<string>10.7</string>
+ <key>NSAppTransportSecurity</key>
+ <dict>
+ <key>NSAllowsArbitraryLoads</key>
+ <true/>
+ </dict>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
diff --git a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/MacOS/ZeroTier One b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/MacOS/ZeroTier One
index 429efc0b..ba15bca9 100755
--- a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/MacOS/ZeroTier One
+++ b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/MacOS/ZeroTier One
Binary files differ
diff --git a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/MainMenu.nib b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/MainMenu.nib
index 4cd319b2..bac7faa7 100644
--- a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/MainMenu.nib
+++ b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/MainMenu.nib
Binary files differ
diff --git a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/Window.nib b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/Window.nib
index 559409d9..69258da6 100644
--- a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/Window.nib
+++ b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/Resources/en.lproj/Window.nib
Binary files differ
diff --git a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/_CodeSignature/CodeResources b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/_CodeSignature/CodeResources
index bd79b1f3..14556923 100644
--- a/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/_CodeSignature/CodeResources
+++ b/ext/mac-ui-macgap1-wrapper/bin/ZeroTier One.app/Contents/_CodeSignature/CodeResources
@@ -30,7 +30,7 @@
<dict>
<key>hash</key>
<data>
- kkFJZm0JXF9gTUF2keyMJQ9p9SY=
+ 8JZXf4/3df3LD+o74Y8WM0dV8io=
</data>
<key>optional</key>
<true/>
@@ -39,7 +39,7 @@
<dict>
<key>hash</key>
<data>
- 42zB9+COYMmPW0WlnU1juN2B9SA=
+ 7dgumnPDtoIzhi9QoaFhDvCo9ys=
</data>
<key>optional</key>
<true/>
@@ -73,7 +73,7 @@
<dict>
<key>hash</key>
<data>
- kkFJZm0JXF9gTUF2keyMJQ9p9SY=
+ 8JZXf4/3df3LD+o74Y8WM0dV8io=
</data>
<key>optional</key>
<true/>
@@ -82,7 +82,7 @@
<dict>
<key>hash</key>
<data>
- 42zB9+COYMmPW0WlnU1juN2B9SA=
+ 7dgumnPDtoIzhi9QoaFhDvCo9ys=
</data>
<key>optional</key>
<true/>
diff --git a/ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/project.pbxproj b/ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/project.pbxproj
index 08d72d06..775c5964 100644
--- a/ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/project.pbxproj
+++ b/ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/project.pbxproj
@@ -269,7 +269,7 @@
FAE451B114BA79C600190544 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0450;
+ LastUpgradeCheck = 0710;
ORGANIZATIONNAME = Twitter;
};
buildConfigurationList = FAE451B414BA79C600190544 /* Build configuration list for PBXProject "MacGap" */;
@@ -374,9 +374,9 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_ENABLE_OBJC_ARC = YES;
COPY_PHASE_STRIP = NO;
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -402,7 +402,6 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_ENABLE_OBJC_ARC = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
@@ -434,6 +433,7 @@
GCC_VERSION = "";
INFOPLIST_FILE = "MacGap/MacGap-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.7;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.zerotier.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "ZeroTier One";
SDKROOT = macosx;
WRAPPER_EXTENSION = app;
@@ -455,6 +455,7 @@
GCC_VERSION = "";
INFOPLIST_FILE = "MacGap/MacGap-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.7;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.zerotier.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "ZeroTier One";
SDKROOT = macosx;
WRAPPER_EXTENSION = app;
diff --git a/ext/mac-ui-macgap1-wrapper/src/MacGap/AppDelegate.m b/ext/mac-ui-macgap1-wrapper/src/MacGap/AppDelegate.m
index 3e25ca13..45923bb3 100644
--- a/ext/mac-ui-macgap1-wrapper/src/MacGap/AppDelegate.m
+++ b/ext/mac-ui-macgap1-wrapper/src/MacGap/AppDelegate.m
@@ -32,6 +32,7 @@
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification {
char buf[16384],userAuthTokenPath[4096];
+ struct stat systemAuthTokenStat,userAuthTokenStat;
FILE *pf = fopen("/Library/Application Support/ZeroTier/One/zerotier-one.port","r");
long port = 9993; // default
@@ -50,14 +51,27 @@
const char *homeDir = getenv("HOME");
if (homeDir) {
snprintf(userAuthTokenPath,sizeof(userAuthTokenPath),"%s/Library/Application Support/ZeroTier/One/authtoken.secret",homeDir);
- pf = fopen(userAuthTokenPath,"r");
- if (pf) {
- long n = fread(buf,1,sizeof(buf)-1,pf);
- if (n > 0) {
- buf[n] = (char)0;
- snprintf(url,sizeof(url),"http://127.0.0.1:%ld/index.html?authToken=%s",port,buf);
+
+ bool userAuthTokenOutOfDate = false;
+ memset(&systemAuthTokenStat,0,sizeof(systemAuthTokenStat));
+ memset(&userAuthTokenStat,0,sizeof(userAuthTokenStat));
+ if (stat("/Library/Application Support/ZeroTier/One/authtoken.secret",&systemAuthTokenStat) == 0) {
+ if (stat(userAuthTokenPath,&userAuthTokenStat) == 0) {
+ if (userAuthTokenStat.st_mtimespec.tv_sec < systemAuthTokenStat.st_mtimespec.tv_sec)
+ userAuthTokenOutOfDate = true;
+ }
+ }
+
+ if (!userAuthTokenOutOfDate) {
+ pf = fopen(userAuthTokenPath,"r");
+ if (pf) {
+ long n = fread(buf,1,sizeof(buf)-1,pf);
+ if (n > 0) {
+ buf[n] = (char)0;
+ snprintf(url,sizeof(url),"http://127.0.0.1:%ld/index.html?authToken=%s",port,buf);
+ }
+ fclose(pf);
}
- fclose(pf);
}
}
diff --git a/ext/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.m b/ext/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.m
index 24e58cd1..6558a191 100644
--- a/ext/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.m
+++ b/ext/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.m
@@ -39,11 +39,11 @@
[self.webView setApplicationNameForUserAgent: @"MacGap"];
self.delegate = [[WebViewDelegate alloc] initWithMenu:[NSApp mainMenu]];
- [self.webView setFrameLoadDelegate:self.delegate];
- [self.webView setUIDelegate:self.delegate];
- [self.webView setResourceLoadDelegate:self.delegate];
- [self.webView setDownloadDelegate:self.delegate];
- [self.webView setPolicyDelegate:self.delegate];
+// [self.webView setFrameLoadDelegate:self.delegate];
+// [self.webView setUIDelegate:self.delegate];
+// [self.webView setResourceLoadDelegate:self.delegate];
+// [self.webView setDownloadDelegate:self.delegate];
+// [self.webView setPolicyDelegate:self.delegate];
[self.webView setDrawsBackground:NO];
[self.webView setShouldCloseWithWindow:NO];
diff --git a/ext/mac-ui-macgap1-wrapper/src/MacGap/MacGap-Info.plist b/ext/mac-ui-macgap1-wrapper/src/MacGap/MacGap-Info.plist
index 7e10a7a6..7f71ea22 100644
--- a/ext/mac-ui-macgap1-wrapper/src/MacGap/MacGap-Info.plist
+++ b/ext/mac-ui-macgap1-wrapper/src/MacGap/MacGap-Info.plist
@@ -2,14 +2,14 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
- <key>CFBundleIconFile</key>
- <string>ZeroTierIcon</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>ZeroTier One</string>
+ <key>CFBundleIconFile</key>
+ <string>ZeroTierIcon</string>
<key>CFBundleIdentifier</key>
- <string>com.zerotier.$(PRODUCT_NAME:rfc1034identifier)</string>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -30,5 +30,10 @@
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
+ <key>NSAppTransportSecurity</key>
+ <dict>
+ <key>NSAllowsArbitraryLoads</key>
+ <true/>
+ </dict>
</dict>
</plist>
diff --git a/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/Window.xib b/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/Window.xib
index 70d0c57b..2c46b79f 100644
--- a/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/Window.xib
+++ b/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/Window.xib
@@ -1,337 +1,44 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
- <data>
- <int key="IBDocument.SystemTarget">1070</int>
- <string key="IBDocument.SystemVersion">11C74</string>
- <string key="IBDocument.InterfaceBuilderVersion">1938</string>
- <string key="IBDocument.AppKitVersion">1138.23</string>
- <string key="IBDocument.HIToolboxVersion">567.00</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.WebKitIBPlugin</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>1938</string>
- <string>822</string>
- </object>
- </object>
- <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>NSWindowTemplate</string>
- <string>NSView</string>
- <string>NSCustomObject</string>
- <string>WebView</string>
- </object>
- <object class="NSArray" key="IBDocument.PluginDependencies">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.WebKitIBPlugin</string>
- </object>
- <object class="NSMutableDictionary" key="IBDocument.Metadata">
- <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
- <integer value="1" key="NS.object.0"/>
- </object>
- <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSCustomObject" id="1001">
- <string key="NSClassName">WindowController</string>
- </object>
- <object class="NSCustomObject" id="1003">
- <string key="NSClassName">FirstResponder</string>
- </object>
- <object class="NSCustomObject" id="1004">
- <string key="NSClassName">NSApplication</string>
- </object>
- <object class="NSWindowTemplate" id="1005">
- <int key="NSWindowStyleMask">15</int>
- <int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{196, 240}, {758, 410}}</string>
- <int key="NSWTFlags">544735232</int>
- <string key="NSWindowTitle">Window</string>
- <string key="NSWindowClass">NSWindow</string>
- <nil key="NSViewClass"/>
- <nil key="NSUserInterfaceItemIdentifier"/>
- <object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
- <int key="NSvFlags">256</int>
- <object class="NSMutableArray" key="NSSubviews">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="WebView" id="807146547">
- <reference key="NSNextResponder" ref="1006"/>
- <int key="NSvFlags">274</int>
- <object class="NSMutableSet" key="NSDragTypes">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="set.sortedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>Apple HTML pasteboard type</string>
- <string>Apple PDF pasteboard type</string>
- <string>Apple PICT pasteboard type</string>
- <string>Apple URL pasteboard type</string>
- <string>Apple Web Archive pasteboard type</string>
- <string>NSColor pasteboard type</string>
- <string>NSFilenamesPboardType</string>
- <string>NSStringPboardType</string>
- <string>NeXT RTFD pasteboard type</string>
- <string>NeXT Rich Text Format v1.0 pasteboard type</string>
- <string>NeXT TIFF v4.0 pasteboard type</string>
- <string>WebURLsWithTitlesPboardType</string>
- <string>public.png</string>
- <string>public.url</string>
- <string>public.url-name</string>
- </object>
- </object>
- <string key="NSFrameSize">{758, 410}</string>
- <reference key="NSSuperview" ref="1006"/>
- <reference key="NSWindow"/>
- <reference key="NSNextKeyView"/>
- <int key="NSViewLayerContentsRedrawPolicy">2</int>
- <string key="NSReuseIdentifierKey">_NS:51</string>
- <string key="FrameName"/>
- <string key="GroupName"/>
- <object class="WebPreferences" key="Preferences">
- <string key="Identifier"/>
- <object class="NSMutableDictionary" key="Values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>WebKitDefaultFixedFontSize</string>
- <string>WebKitDefaultFontSize</string>
- <string>WebKitMinimumFontSize</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="12"/>
- <integer value="12"/>
- <integer value="1"/>
- </object>
- </object>
- </object>
- <bool key="UseBackForwardList">YES</bool>
- <bool key="AllowsUndo">YES</bool>
- </object>
- </object>
- <string key="NSFrameSize">{758, 410}</string>
- <reference key="NSSuperview"/>
- <reference key="NSWindow"/>
- <reference key="NSNextKeyView" ref="807146547"/>
- </object>
- <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
- <string key="NSMaxSize">{10000000000000, 10000000000000}</string>
- <int key="NSWindowCollectionBehavior">128</int>
- <bool key="NSWindowIsRestorable">YES</bool>
- </object>
- </object>
- <object class="IBObjectContainer" key="IBDocument.Objects">
- <object class="NSMutableArray" key="connectionRecords">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">contentView</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1006"/>
- </object>
- <int key="connectionID">23</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">window</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1005"/>
- </object>
- <int key="connectionID">25</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">title: contentView.webView.mainFrameTitle</string>
- <reference key="source" ref="1005"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="1005"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">title: contentView.webView.mainFrameTitle</string>
- <string key="NSBinding">title</string>
- <string key="NSKeyPath">contentView.webView.mainFrameTitle</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">31</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">webView</string>
- <reference key="source" ref="1006"/>
- <reference key="destination" ref="807146547"/>
- </object>
- <int key="connectionID">19</int>
- </object>
- </object>
- <object class="IBMutableOrderedSet" key="objectRecords">
- <object class="NSArray" key="orderedObjects">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBObjectRecord">
- <int key="objectID">0</int>
- <object class="NSArray" key="object" id="1002">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
- <reference key="children" ref="1000"/>
- <nil key="parent"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-2</int>
- <reference key="object" ref="1001"/>
- <reference key="parent" ref="1002"/>
- <string key="objectName">File's Owner</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-1</int>
- <reference key="object" ref="1003"/>
- <reference key="parent" ref="1002"/>
- <string key="objectName">First Responder</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="1004"/>
- <reference key="parent" ref="1002"/>
- <string key="objectName">Application</string>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">1</int>
- <reference key="object" ref="1005"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1006"/>
- </object>
- <reference key="parent" ref="1002"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">2</int>
- <reference key="object" ref="1006"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="807146547"/>
- </object>
- <reference key="parent" ref="1005"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">5</int>
- <reference key="object" ref="807146547"/>
- <reference key="parent" ref="1006"/>
- </object>
- </object>
- </object>
- <object class="NSMutableDictionary" key="flattenedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>-1.IBPluginDependency</string>
- <string>-2.IBPluginDependency</string>
- <string>-3.IBPluginDependency</string>
- <string>1.IBPluginDependency</string>
- <string>1.IBWindowTemplateEditedContentRect</string>
- <string>1.NSWindowTemplate.visibleAtLaunch</string>
- <string>2.CustomClassName</string>
- <string>2.IBPluginDependency</string>
- <string>5.IBPluginDependency</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{357, 418}, {480, 270}}</string>
- <integer value="1"/>
- <string>ContentView</string>
- <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>com.apple.WebKitIBPlugin</string>
- </object>
- </object>
- <object class="NSMutableDictionary" key="unlocalizedProperties">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="1002"/>
- <reference key="dict.values" ref="1002"/>
- </object>
- <nil key="activeLocalization"/>
- <object class="NSMutableDictionary" key="localizations">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference key="dict.sortedKeys" ref="1002"/>
- <reference key="dict.values" ref="1002"/>
- </object>
- <nil key="sourceID"/>
- <int key="maxID">31</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">ContentView</string>
- <string key="superclassName">NSView</string>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">webView</string>
- <string key="NS.object.0">WebView</string>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <string key="NS.key.0">webView</string>
- <object class="IBToOneOutletInfo" key="NS.object.0">
- <string key="name">webView</string>
- <string key="candidateClassName">WebView</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">./Classes/ContentView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">WebView</string>
- <object class="NSMutableDictionary" key="actions">
- <string key="NS.key.0">reloadFromOrigin:</string>
- <string key="NS.object.0">id</string>
- </object>
- <object class="NSMutableDictionary" key="actionInfosByName">
- <string key="NS.key.0">reloadFromOrigin:</string>
- <object class="IBActionInfo" key="NS.object.0">
- <string key="name">reloadFromOrigin:</string>
- <string key="candidateClassName">id</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">./Classes/WebView.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">WindowController</string>
- <string key="superclassName">NSWindowController</string>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">contentView</string>
- <string key="NS.object.0">ContentView</string>
- </object>
- <object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <string key="NS.key.0">contentView</string>
- <object class="IBToOneOutletInfo" key="NS.object.0">
- <string key="name">contentView</string>
- <string key="candidateClassName">ContentView</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">./Classes/WindowController.h</string>
- </object>
- </object>
- </object>
- </object>
- <int key="IBDocument.localizationMode">0</int>
- <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
- <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
- <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
- <integer value="3000" key="NS.object.0"/>
- </object>
- <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <int key="IBDocument.defaultPropertyAccessControl">3</int>
- </data>
-</archive>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+ <dependencies>
+ <deployment identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9060"/>
+ <plugIn identifier="com.apple.WebKitIBPlugin" version="9060"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="WindowController">
+ <connections>
+ <outlet property="contentView" destination="2" id="23"/>
+ <outlet property="window" destination="1" id="25"/>
+ </connections>
+ </customObject>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application"/>
+ <window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" animationBehavior="default" id="1">
+ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
+ <rect key="contentRect" x="575" y="564" width="500" height="700"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
+ <value key="minSize" type="size" width="500" height="700"/>
+ <value key="maxSize" type="size" width="500" height="700"/>
+ <view key="contentView" id="2" customClass="ContentView">
+ <rect key="frame" x="0.0" y="0.0" width="500" height="700"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <webView id="5">
+ <rect key="frame" x="0.0" y="0.0" width="500" height="700"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <animations/>
+ <webPreferences key="preferences" defaultFontSize="12" defaultFixedFontSize="12"/>
+ </webView>
+ </subviews>
+ <animations/>
+ <connections>
+ <outlet property="webView" destination="5" id="19"/>
+ </connections>
+ </view>
+ <connections>
+ <binding destination="-2" name="title" keyPath="contentView.webView.mainFrameTitle" id="31"/>
+ </connections>
+ </window>
+ </objects>
+</document>
diff --git a/ext/miniupnpc/CMakeLists.txt b/ext/miniupnpc/CMakeLists.txt
new file mode 100644
index 00000000..dacb1f69
--- /dev/null
+++ b/ext/miniupnpc/CMakeLists.txt
@@ -0,0 +1,178 @@
+cmake_minimum_required (VERSION 2.6)
+
+project (miniupnpc C)
+set (MINIUPNPC_VERSION 1.9)
+set (MINIUPNPC_API_VERSION 15)
+
+if (NOT CMAKE_BUILD_TYPE)
+ if (WIN32)
+ set (DEFAULT_BUILD_TYPE MinSizeRel)
+ else (WIN32)
+ set (DEFAULT_BUILD_TYPE RelWithDebInfo)
+ endif(WIN32)
+ set (CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING
+ "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
+ FORCE)
+endif()
+
+option (UPNPC_BUILD_STATIC "Build static library" TRUE)
+option (UPNPC_BUILD_SHARED "Build shared library" TRUE)
+if (NOT WIN32)
+ option (UPNPC_BUILD_TESTS "Build test executables" TRUE)
+endif (NOT WIN32)
+option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE)
+
+mark_as_advanced (NO_GETADDRINFO)
+
+if (NO_GETADDRINFO)
+ add_definitions (-DNO_GETADDRINFO)
+endif (NO_GETADDRINFO)
+
+if (NOT WIN32)
+ add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT)
+ add_definitions (-D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L)
+else (NOT WIN32)
+ add_definitions (-D_WIN32_WINNT=0x0501) # XP or higher for getnameinfo and friends
+endif (NOT WIN32)
+
+if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ add_definitions (-D_DARWIN_C_SOURCE)
+endif ()
+
+# Set compiler specific build flags
+if (CMAKE_COMPILER_IS_GNUC)
+ # Set our own default flags at first run.
+ if (NOT CONFIGURED)
+
+ if (NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
+ set (_PIC -fPIC)
+ endif (CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
+
+ set (CMAKE_C_FLAGS "${_PIC} -Wall $ENV{CFLAGS}" # CMAKE_C_FLAGS gets appended to the other C flags
+ CACHE STRING "Flags used by the C compiler during normal builds." FORCE)
+ set (CMAKE_C_FLAGS_DEBUG "-g -DDDEBUG"
+ CACHE STRING "Flags used by the C compiler during debug builds." FORCE)
+ set (CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG"
+ CACHE STRING "Flags used by the C compiler during release builds." FORCE)
+ set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG"
+ CACHE STRING "Flags used by the C compiler during release builds." FORCE)
+ set (CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG"
+ CACHE STRING "Flags used by the C compiler during release builds." FORCE)
+
+ endif (NOT CONFIGURED)
+endif ()
+
+configure_file (${CMAKE_SOURCE_DIR}/miniupnpcstrings.h.cmake ${CMAKE_BINARY_DIR}/miniupnpcstrings.h)
+include_directories (${CMAKE_BINARY_DIR})
+
+set (MINIUPNPC_SOURCES
+ igd_desc_parse.c
+ miniupnpc.c
+ minixml.c
+ minisoap.c
+ minissdpc.c
+ miniwget.c
+ upnpc.c
+ upnpcommands.c
+ upnpdev.c
+ upnpreplyparse.c
+ upnperrors.c
+ connecthostport.c
+ portlistingparse.c
+ receivedata.c
+)
+
+if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
+ set (MINIUPNPC_SOURCES ${MINIUPNPC_SOURCES} minissdpc.c)
+endif (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
+
+if (WIN32)
+ set_source_files_properties (${MINIUPNPC_SOURCES} PROPERTIES
+ COMPILE_DEFINITIONS "MINIUPNP_STATICLIB;MINIUPNP_EXPORTS"
+ )
+endif (WIN32)
+
+if (WIN32)
+ find_library (WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32)
+ find_library (IPHLPAPI_LIBRARY NAMES iphlpapi)
+ set (LDLIBS ${WINSOCK2_LIBRARY} ${IPHLPAPI_LIBRARY} ${LDLIBS})
+#elseif (CMAKE_SYSTEM_NAME STREQUAL "Solaris")
+# find_library (SOCKET_LIBRARY NAMES socket)
+# find_library (NSL_LIBRARY NAMES nsl)
+# find_library (RESOLV_LIBRARY NAMES resolv)
+# set (LDLIBS ${SOCKET_LIBRARY} ${NSL_LIBRARY} ${RESOLV_LIBRARY} ${LDLIBS})
+endif (WIN32)
+
+if (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED)
+ message (FATAL "Both shared and static libraries are disabled!")
+endif (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED)
+
+if (UPNPC_BUILD_STATIC)
+ add_library (upnpc-static STATIC ${MINIUPNPC_SOURCES})
+ set_target_properties (upnpc-static PROPERTIES OUTPUT_NAME "miniupnpc")
+ target_link_libraries (upnpc-static ${LDLIBS})
+ set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-static)
+ set (UPNPC_LIBRARY_TARGET upnpc-static)
+endif (UPNPC_BUILD_STATIC)
+
+if (UPNPC_BUILD_SHARED)
+ add_library (upnpc-shared SHARED ${MINIUPNPC_SOURCES})
+ set_target_properties (upnpc-shared PROPERTIES OUTPUT_NAME "miniupnpc")
+ set_target_properties (upnpc-shared PROPERTIES VERSION ${MINIUPNPC_VERSION})
+ set_target_properties (upnpc-shared PROPERTIES SOVERSION ${MINIUPNPC_API_VERSION})
+ target_link_libraries (upnpc-shared ${LDLIBS})
+ set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-shared)
+ set (UPNPC_LIBRARY_TARGET upnpc-shared)
+endif (UPNPC_BUILD_SHARED)
+
+if (UPNPC_BUILD_TESTS)
+ add_executable (testminixml testminixml.c minixml.c igd_desc_parse.c)
+ target_link_libraries (testminixml ${LDLIBS})
+
+ add_executable (minixmlvalid minixmlvalid.c minixml.c)
+ target_link_libraries (minixmlvalid ${LDLIBS})
+
+ add_executable (testupnpreplyparse testupnpreplyparse.c
+ minixml.c upnpreplyparse.c)
+ target_link_libraries (testupnpreplyparse ${LDLIBS})
+
+ add_executable (testigddescparse testigddescparse.c
+ igd_desc_parse.c minixml.c miniupnpc.c miniwget.c minissdpc.c
+ upnpcommands.c upnpreplyparse.c minisoap.c connecthostport.c
+ portlistingparse.c receivedata.c
+ )
+ target_link_libraries (testigddescparse ${LDLIBS})
+
+ add_executable (testminiwget testminiwget.c
+ miniwget.c miniupnpc.c minisoap.c upnpcommands.c minissdpc.c
+ upnpreplyparse.c minixml.c igd_desc_parse.c connecthostport.c
+ portlistingparse.c receivedata.c
+ )
+ target_link_libraries (testminiwget ${LDLIBS})
+
+# set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} testminixml minixmlvalid testupnpreplyparse testigddescparse testminiwget)
+endif (UPNPC_BUILD_TESTS)
+
+
+install (TARGETS ${UPNPC_INSTALL_TARGETS}
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib${LIB_SUFFIX}
+ ARCHIVE DESTINATION lib${LIB_SUFFIX}
+)
+install (FILES
+ miniupnpc.h
+ miniwget.h
+ upnpcommands.h
+ igd_desc_parse.h
+ upnpreplyparse.h
+ upnperrors.h
+ upnpdev.h
+ miniupnpctypes.h
+ portlistingparse.h
+ miniupnpc_declspec.h
+ DESTINATION include/miniupnpc
+)
+
+set (CONFIGURED YES CACHE INTERNAL "")
+
+# vim: ts=2:sw=2
diff --git a/ext/bin/miniupnpc/Changelog.txt b/ext/miniupnpc/Changelog.txt
index bb2abb7e..bef61f59 100644
--- a/ext/bin/miniupnpc/Changelog.txt
+++ b/ext/miniupnpc/Changelog.txt
@@ -1,6 +1,40 @@
-$Id: Changelog.txt,v 1.208 2015/07/15 12:18:59 nanard Exp $
+$Id: Changelog.txt,v 1.219 2015/10/26 17:05:06 nanard Exp $
miniUPnP client Changelog.
+2015/10/26:
+ snprintf() overflow check. check overflow in simpleUPnPcommand2()
+
+2015/10/25:
+ fix compilation with old macs
+ fix compilation with mingw32 (for Appveyor)
+ fix python module for python <= 2.3
+
+2015/10/08:
+ Change sameport to localport
+ see https://github.com/miniupnp/miniupnp/pull/120
+ increments API_VERSION to 15
+
+2015/09/15:
+ Fix buffer overflow in igd_desc_parse.c/IGDstartelt()
+ Discovered by Aleksandar Nikolic of Cisco Talos
+
+2015/08/28:
+ move ssdpDiscoverDevices() to minissdpc.c
+
+2015/08/27:
+ avoid unix socket leak in getDevicesFromMiniSSDPD()
+
+2015/08/16:
+ Also accept "Up" as ConnectionStatus value
+
+2015/07/23:
+ split getDevicesFromMiniSSDPD
+ add ttl argument to upnpDiscover() functions
+ increments API_VERSION to 14
+
+2015/07/22:
+ Read USN from SSDP messages.
+
2015/07/15:
Check malloc/calloc
diff --git a/ext/bin/miniupnpc/LICENSE b/ext/miniupnpc/LICENSE
index cb5a0604..cb5a0604 100644
--- a/ext/bin/miniupnpc/LICENSE
+++ b/ext/miniupnpc/LICENSE
diff --git a/ext/miniupnpc/MANIFEST.in b/ext/miniupnpc/MANIFEST.in
new file mode 100644
index 00000000..54b86f95
--- /dev/null
+++ b/ext/miniupnpc/MANIFEST.in
@@ -0,0 +1,5 @@
+include README
+include miniupnpcmodule.c
+include setup.py
+include *.h
+include libminiupnpc.a
diff --git a/ext/miniupnpc/Makefile b/ext/miniupnpc/Makefile
new file mode 100644
index 00000000..4a4f1612
--- /dev/null
+++ b/ext/miniupnpc/Makefile
@@ -0,0 +1,379 @@
+# $Id: Makefile,v 1.132 2015/10/26 16:59:54 nanard Exp $
+# MiniUPnP Project
+# http://miniupnp.free.fr/
+# http://miniupnp.tuxfamily.org/
+# https://github.com/miniupnp/miniupnp
+# (c) 2005-2015 Thomas Bernard
+# to install use :
+# $ make DESTDIR=/tmp/dummylocation install
+# or
+# $ INSTALLPREFIX=/usr/local make install
+# or
+# $ make install (default INSTALLPREFIX is /usr)
+OS = $(shell uname -s)
+VERSION = $(shell cat VERSION)
+
+ifeq ($(OS), Darwin)
+JARSUFFIX=mac
+LIBTOOL ?= $(shell which libtool)
+endif
+ifeq ($(OS), Linux)
+JARSUFFIX=linux
+endif
+ifneq (,$(findstring NT-5.1,$(OS)))
+JARSUFFIX=win32
+endif
+
+HAVE_IPV6 ?= yes
+export HAVE_IPV6
+
+CC ?= gcc
+#AR = gar
+#CFLAGS = -O -g -DDEBUG
+CFLAGS ?= -O
+CFLAGS += -Wall
+CFLAGS += -W -Wstrict-prototypes
+CFLAGS += -fno-common
+CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT
+CFLAGS += -DMINIUPNPC_GET_SRC_ADDR
+CFLAGS += -D_BSD_SOURCE
+CFLAGS += -D_DEFAULT_SOURCE
+ifneq ($(OS), FreeBSD)
+ifneq ($(OS), Darwin)
+#CFLAGS += -D_POSIX_C_SOURCE=200112L
+CFLAGS += -D_XOPEN_SOURCE=600
+endif
+endif
+#CFLAGS += -ansi
+# -DNO_GETADDRINFO
+INSTALL = install
+SH = /bin/sh
+JAVA = java
+# see http://code.google.com/p/jnaerator/
+#JNAERATOR = jnaerator-0.9.7.jar
+#JNAERATOR = jnaerator-0.9.8-shaded.jar
+#JNAERATORARGS = -library miniupnpc
+#JNAERATOR = jnaerator-0.10-shaded.jar
+#JNAERATOR = jnaerator-0.11-shaded.jar
+# https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12/jnaerator-0.12-shaded.jar
+JNAERATOR = jnaerator-0.12-shaded.jar
+JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc
+#JNAERATORBASEURL = http://jnaerator.googlecode.com/files/
+JNAERATORBASEURL = https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12
+
+ifeq (SunOS, $(OS))
+ LDFLAGS=-lsocket -lnsl -lresolv
+endif
+
+# APIVERSION is used to build SONAME
+APIVERSION = 15
+
+SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
+ upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \
+ minixmlvalid.c testupnpreplyparse.c minissdpc.c \
+ upnperrors.c testigddescparse.c testminiwget.c \
+ connecthostport.c portlistingparse.c receivedata.c \
+ upnpdev.c testportlistingparse.c miniupnpcmodule.c \
+ minihttptestserver.c \
+ listdevices.c
+
+LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \
+ miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
+ connecthostport.o portlistingparse.o receivedata.o upnpdev.o
+
+ifneq ($(OS), AmigaOS)
+CFLAGS := -fPIC $(CFLAGS)
+LIBOBJS := $(LIBOBJS) minissdpc.o
+endif
+
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+
+# HEADERS to install
+HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
+ upnpreplyparse.h upnperrors.h miniupnpctypes.h \
+ portlistingparse.h \
+ upnpdev.h \
+ miniupnpc_declspec.h
+
+# library names
+LIBRARY = libminiupnpc.a
+ifeq ($(OS), Darwin)
+ SHAREDLIBRARY = libminiupnpc.dylib
+ SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib
+ CFLAGS := -D_DARWIN_C_SOURCE $(CFLAGS)
+else
+ifeq ($(JARSUFFIX), win32)
+ SHAREDLIBRARY = miniupnpc.dll
+else
+ # Linux/BSD/etc.
+ SHAREDLIBRARY = libminiupnpc.so
+ SONAME = $(SHAREDLIBRARY).$(APIVERSION)
+endif
+endif
+
+EXECUTABLES = upnpc-static listdevices
+EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \
+ testigddescparse testminiwget testportlistingparse
+
+TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o
+
+TESTMINIWGETOBJS = miniwget.o testminiwget.o connecthostport.o receivedata.o
+
+TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o
+
+TESTPORTLISTINGPARSE = testportlistingparse.o minixml.o portlistingparse.o
+
+TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \
+ miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \
+ minisoap.o connecthostport.o receivedata.o \
+ portlistingparse.o
+
+ifneq ($(OS), AmigaOS)
+EXECUTABLES := $(EXECUTABLES) upnpc-shared
+TESTMINIWGETOBJS := $(TESTMINIWGETOBJS) minissdpc.o
+TESTIGDDESCPARSE := $(TESTIGDDESCPARSE) minissdpc.o
+endif
+
+LIBDIR ?= lib
+# install directories
+INSTALLPREFIX ?= $(PREFIX)/usr
+INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc
+INSTALLDIRLIB = $(INSTALLPREFIX)/$(LIBDIR)
+INSTALLDIRBIN = $(INSTALLPREFIX)/bin
+INSTALLDIRMAN = $(INSTALLPREFIX)/share/man
+
+FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES)
+ifneq ($(OS), AmigaOS)
+FILESTOINSTALL := $(FILESTOINSTALL) $(SHAREDLIBRARY)
+endif
+
+
+.PHONY: install clean depend all check test everything \
+ installpythonmodule updateversion
+# validateminixml validateminiwget
+
+all: $(LIBRARY) $(EXECUTABLES)
+
+test: check
+
+check: validateminixml validateminiwget validateupnpreplyparse \
+ validateportlistingparse validateigddescparse
+
+everything: all $(EXECUTABLES_ADDTESTS)
+
+pythonmodule: $(LIBRARY) miniupnpcmodule.c setup.py
+ python setup.py build
+ touch $@
+
+installpythonmodule: pythonmodule
+ python setup.py install
+
+pythonmodule3: $(LIBRARY) miniupnpcmodule.c setup.py
+ python3 setup.py build
+ touch $@
+
+installpythonmodule3: pythonmodule3
+ python3 setup.py install
+
+validateminixml: minixmlvalid
+ @echo "minixml validation test"
+ ./minixmlvalid
+ touch $@
+
+validateminiwget: testminiwget minihttptestserver testminiwget.sh
+ @echo "miniwget validation test"
+ ./testminiwget.sh
+ touch $@
+
+validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh
+ @echo "upnpreplyparse validation test"
+ ./testupnpreplyparse.sh
+ touch $@
+
+validateportlistingparse: testportlistingparse
+ @echo "portlistingparse validation test"
+ ./testportlistingparse
+ touch $@
+
+validateigddescparse: testigddescparse
+ @echo "igd desc parse validation test"
+ ./testigddescparse testdesc/new_LiveBox_desc.xml testdesc/new_LiveBox_desc.values
+ ./testigddescparse testdesc/linksys_WAG200G_desc.xml testdesc/linksys_WAG200G_desc.values
+ touch $@
+
+clean:
+ $(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
+ $(RM) $(EXECUTABLES_ADDTESTS)
+ # clean python stuff
+ $(RM) pythonmodule pythonmodule3
+ $(RM) validateminixml validateminiwget validateupnpreplyparse
+ $(RM) validateigddescparse
+ $(RM) minihttptestserver
+ $(RM) -r build/ dist/
+ #python setup.py clean
+ # clean jnaerator stuff
+ $(RM) _jnaerator.* java/miniupnpc_$(OS).jar
+
+distclean: clean
+ $(RM) $(JNAERATOR) java/*.jar java/*.class out.errors.txt
+
+updateversion: miniupnpc.h
+ cp miniupnpc.h miniupnpc.h.bak
+ sed 's/\(.*MINIUPNPC_API_VERSION\s\+\)[0-9]\+/\1$(APIVERSION)/' < miniupnpc.h.bak > miniupnpc.h
+
+install: updateversion $(FILESTOINSTALL)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
+ $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
+ $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
+ifneq ($(OS), AmigaOS)
+ $(INSTALL) -m 644 $(SHAREDLIBRARY) $(DESTDIR)$(INSTALLDIRLIB)/$(SONAME)
+ ln -fs $(SONAME) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
+endif
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
+ifeq ($(OS), AmigaOS)
+ $(INSTALL) -m 755 upnpc-static $(DESTDIR)$(INSTALLDIRBIN)/upnpc
+else
+ $(INSTALL) -m 755 upnpc-shared $(DESTDIR)$(INSTALLDIRBIN)/upnpc
+endif
+ $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
+ifneq ($(OS), AmigaOS)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3
+ $(INSTALL) -m 644 man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
+ifeq ($(OS), Linux)
+ gzip -f $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
+endif
+endif
+
+install-static: updateversion $(FILESTOINSTALL)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
+ $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
+ $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
+ $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
+ $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
+
+cleaninstall:
+ $(RM) -r $(DESTDIR)$(INSTALLDIRINC)
+ $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY)
+ $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
+
+depend:
+ makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
+
+$(LIBRARY): $(LIBOBJS)
+ifeq ($(OS), Darwin)
+ $(LIBTOOL) -static -o $@ $?
+else
+ $(AR) crs $@ $?
+endif
+
+$(SHAREDLIBRARY): $(LIBOBJS)
+ifeq ($(OS), Darwin)
+# $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(SONAME) -o $@ $^
+ $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(INSTALLDIRLIB)/$(SONAME) -o $@ $^
+else
+ $(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^
+endif
+
+upnpc-static: upnpc.o $(LIBRARY)
+ $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
+
+upnpc-shared: upnpc.o $(SHAREDLIBRARY)
+ $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
+
+listdevices: listdevices.o $(LIBRARY)
+
+testminixml: $(TESTMINIXMLOBJS)
+
+testminiwget: $(TESTMINIWGETOBJS)
+
+minixmlvalid: minixml.o minixmlvalid.o
+
+testupnpreplyparse: $(TESTUPNPREPLYPARSE)
+
+testigddescparse: $(TESTIGDDESCPARSE)
+
+testportlistingparse: $(TESTPORTLISTINGPARSE)
+
+miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION
+ $(SH) updateminiupnpcstrings.sh
+
+# ftp tool supplied with OpenBSD can download files from http.
+jnaerator-%.jar:
+ wget $(JNAERATORBASEURL)/$@ || \
+ curl -o $@ $(JNAERATORBASEURL)/$@ || \
+ ftp $(JNAERATORBASEURL)/$@
+
+jar: $(SHAREDLIBRARY) $(JNAERATOR)
+ $(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \
+ miniupnpc.h miniupnpc_declspec.h upnpcommands.h upnpreplyparse.h \
+ igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \
+ -package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v
+
+mvn_install:
+ mvn install:install-file -Dfile=java/miniupnpc_$(JARSUFFIX).jar \
+ -DgroupId=com.github \
+ -DartifactId=miniupnp \
+ -Dversion=$(VERSION) \
+ -Dpackaging=jar \
+ -Dclassifier=$(JARSUFFIX) \
+ -DgeneratePom=true \
+ -DcreateChecksum=true
+
+# make .deb packages
+deb: /usr/share/pyshared/stdeb all
+ (python setup.py --command-packages=stdeb.command bdist_deb)
+
+# install .deb packages
+ideb:
+ (sudo dpkg -i deb_dist/*.deb)
+
+/usr/share/pyshared/stdeb: /usr/share/doc/python-all-dev
+ (sudo apt-get install python-stdeb)
+
+/usr/share/doc/python-all-dev:
+ (sudo apt-get install python-all-dev)
+
+minihttptestserver: minihttptestserver.o
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+igd_desc_parse.o: igd_desc_parse.h
+miniupnpc.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h
+miniupnpc.o: minissdpc.h miniwget.h minisoap.h minixml.h upnpcommands.h
+miniupnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
+miniupnpc.o: connecthostport.h
+minixml.o: minixml.h
+minisoap.o: minisoap.h miniupnpcstrings.h
+miniwget.o: miniupnpcstrings.h miniwget.h miniupnpc_declspec.h
+miniwget.o: connecthostport.h receivedata.h
+upnpc.o: miniwget.h miniupnpc_declspec.h miniupnpc.h igd_desc_parse.h
+upnpc.o: upnpdev.h upnpcommands.h upnpreplyparse.h portlistingparse.h
+upnpc.o: miniupnpctypes.h upnperrors.h miniupnpcstrings.h
+upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h
+upnpcommands.o: miniupnpc_declspec.h miniupnpctypes.h miniupnpc.h
+upnpcommands.o: igd_desc_parse.h upnpdev.h
+upnpreplyparse.o: upnpreplyparse.h minixml.h
+testminixml.o: minixml.h igd_desc_parse.h
+minixmlvalid.o: minixml.h
+testupnpreplyparse.o: upnpreplyparse.h
+minissdpc.o: minissdpc.h miniupnpc_declspec.h upnpdev.h miniupnpc.h
+minissdpc.o: igd_desc_parse.h receivedata.h codelength.h
+upnperrors.o: upnperrors.h miniupnpc_declspec.h upnpcommands.h
+upnperrors.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
+upnperrors.o: miniupnpc.h igd_desc_parse.h upnpdev.h
+testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h
+testigddescparse.o: miniupnpc_declspec.h upnpdev.h
+testminiwget.o: miniwget.h miniupnpc_declspec.h
+connecthostport.o: connecthostport.h
+portlistingparse.o: portlistingparse.h miniupnpc_declspec.h miniupnpctypes.h
+portlistingparse.o: minixml.h
+receivedata.o: receivedata.h
+upnpdev.o: upnpdev.h miniupnpc_declspec.h
+testportlistingparse.o: portlistingparse.h miniupnpc_declspec.h
+testportlistingparse.o: miniupnpctypes.h
+miniupnpcmodule.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h
+miniupnpcmodule.o: upnpdev.h upnpcommands.h upnpreplyparse.h
+miniupnpcmodule.o: portlistingparse.h miniupnpctypes.h upnperrors.h
+listdevices.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h
diff --git a/ext/miniupnpc/Makefile.mingw b/ext/miniupnpc/Makefile.mingw
new file mode 100644
index 00000000..6de325fe
--- /dev/null
+++ b/ext/miniupnpc/Makefile.mingw
@@ -0,0 +1,98 @@
+# $Id: Makefile.mingw,v 1.22 2015/10/26 16:59:54 nanard Exp $
+# Miniupnp project.
+# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+# (c) 2005-2015 Thomas Bernard
+# This Makefile is made for MinGW
+#
+CC ?= gcc
+#CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501
+CFLAGS = -Wall -Os -DNDEBUG -D_WIN32_WINNT=0X501
+LDLIBS = -lws2_32 -liphlpapi
+# -lwsock32
+# -liphlpapi is needed for GetBestRoute() and GetIpAddrTable()
+PYTHON=\utils\python25\python
+OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \
+ minissdpc.o \
+ miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
+ connecthostport.o portlistingparse.o receivedata.o \
+ upnpdev.o
+OBJSDLL=$(addprefix dll/, $(OBJS))
+
+all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll
+
+init:
+ mkdir dll
+ echo init > init
+
+clean:
+ del upnpc testminixml *.o
+ del dll\*.o
+ del *.exe
+ del miniupnpc.dll
+ del libminiupnpc.a
+
+libminiupnpc.a: $(OBJS)
+ $(AR) cr $@ $?
+
+pythonmodule: libminiupnpc.a
+ $(PYTHON) setupmingw32.py build --compiler=mingw32
+ $(PYTHON) setupmingw32.py install --skip-build
+
+miniupnpc.dll: libminiupnpc.a $(OBJSDLL)
+ dllwrap -k --driver-name gcc \
+ --def miniupnpc.def \
+ --output-def miniupnpc.dll.def \
+ --implib miniupnpc.lib -o $@ \
+ $(OBJSDLL) $(LDLIBS)
+
+miniupnpc.lib: miniupnpc.dll
+# echo $@ generated with $<
+
+dll/upnpc.o: upnpc.o
+# echo $@ generated with $<
+
+.c.o:
+ $(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $<
+ $(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $<
+
+upnpc.o: upnpc.c
+ $(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $<
+ $(CC) $(CFLAGS) -c -o dll/$@ $<
+
+# --enable-stdcall-fixup
+upnpc-static: upnpc.o libminiupnpc.a
+ $(CC) -o $@ $^ $(LDLIBS)
+
+upnpc-shared: dll/upnpc.o miniupnpc.lib
+ $(CC) -o $@ $^ $(LDLIBS)
+
+wingenminiupnpcstrings: wingenminiupnpcstrings.o
+
+wingenminiupnpcstrings.o: wingenminiupnpcstrings.c
+
+miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings
+ wingenminiupnpcstrings $< $@
+
+minixml.o: minixml.c minixml.h
+
+upnpc.o: miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h
+upnpc.o: upnpreplyparse.h upnpcommands.h upnperrors.h miniupnpcstrings.h
+
+miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h
+
+minisoap.o: minisoap.c minisoap.h miniupnpcstrings.h
+
+miniupnpc.o: miniupnpc.c miniupnpc.h minisoap.h miniwget.h minixml.h
+
+igd_desc_parse.o: igd_desc_parse.c igd_desc_parse.h
+
+testminixml: minixml.o igd_desc_parse.o testminixml.c
+
+upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h
+
+upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h
+
+minissdpc.o: minissdpc.c minissdpc.h receivedata.h
+
+upnpdev.o: upnpdev.c upnpdev.h
+
diff --git a/ext/miniupnpc/README b/ext/miniupnpc/README
new file mode 100644
index 00000000..ab08de94
--- /dev/null
+++ b/ext/miniupnpc/README
@@ -0,0 +1,61 @@
+Project: miniupnp
+Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+github: https://github.com/miniupnp/miniupnp
+freecode: http://freecode.com/projects/miniupnp
+Author: Thomas Bernard
+Copyright (c) 2005-2014 Thomas Bernard
+This software is subject to the conditions detailed in the
+LICENSE file provided within this distribution.
+
+
+* miniUPnP Client - miniUPnPc *
+
+To compile, simply run 'gmake' (could be 'make' on your system).
+Under win32, to compile with MinGW, type "mingw32make.bat".
+MS Visual C solution and project files are supplied in the msvc/ subdirectory.
+
+The compilation is known to work under linux, FreeBSD,
+OpenBSD, MacOS X, AmigaOS and cygwin.
+The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3.
+upx (http://upx.sourceforge.net) is used to compress the win32 .exe files.
+
+To install the library and headers on the system use :
+> su
+> make install
+> exit
+
+alternatively, to install into a specific location, use :
+> INSTALLPREFIX=/usr/local make install
+
+upnpc.c is a sample client using the libminiupnpc.
+To use the libminiupnpc in your application, link it with
+libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h,
+upnpcommands.h and miniwget.h :
+- upnpDiscover()
+- miniwget()
+- parserootdesc()
+- GetUPNPUrls()
+- UPNP_* (calling UPNP methods)
+
+Note : use #include <miniupnpc/miniupnpc.h> etc... for the includes
+and -lminiupnpc for the link
+
+Discovery process is speeded up when MiniSSDPd is running on the machine.
+
+
+* Python module *
+
+you can build a python module with 'make pythonmodule'
+and install it with 'make installpythonmodule'.
+setup.py (and setupmingw32.py) are included in the distribution.
+
+
+Feel free to contact me if you have any problem :
+e-mail : miniupnp@free.fr
+
+If you are using libminiupnpc in your application, please
+send me an email !
+
+For any question, you can use the web forum :
+http://miniupnp.tuxfamily.org/forum/
+
diff --git a/ext/bin/miniupnpc/VERSION b/ext/miniupnpc/VERSION
index 2e0e38c6..2e0e38c6 100644
--- a/ext/bin/miniupnpc/VERSION
+++ b/ext/miniupnpc/VERSION
diff --git a/ext/miniupnpc/apiversions.txt b/ext/miniupnpc/apiversions.txt
new file mode 100644
index 00000000..3e9ebef2
--- /dev/null
+++ b/ext/miniupnpc/apiversions.txt
@@ -0,0 +1,167 @@
+$Id: apiversions.txt,v 1.8 2015/10/08 16:15:47 nanard Exp $
+
+Differences in API between miniUPnPc versions
+
+API version 15
+ changed "sameport" argument of upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice()
+ to "localport". When 0 or 1, behaviour is not changed, but it can take
+ any other value between 2 and 65535
+ Existing programs should be compatible
+ updated macro :
+ #define MINIUPNPC_API_VERSION 15
+
+API version 14
+miniupnpc.h
+ add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice()
+ upnpDiscoverDevices()
+ getDevicesFromMiniSSDPD() :
+ connectToMiniSSDPD() / disconnectFromMiniSSDPD()
+ requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD()
+ updated macro :
+ #define MINIUPNPC_API_VERSION 14
+
+API version 13
+miniupnpc.h:
+ add searchalltype param to upnpDiscoverDevices() function
+ updated macro :
+ #define MINIUPNPC_API_VERSION 13
+
+API version 12
+miniupnpc.h :
+ add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices()
+ functions
+ updated macros :
+ #define MINIUPNPC_API_VERSION 12
+
+API version 11
+
+upnpreplyparse.h / portlistingparse.h :
+ removed usage of sys/queue.h / bsdqueue.h
+
+miniupnpc.h:
+ updated macros :
+ #define MINIUPNPC_API_VERSION 11
+
+====================== miniUPnPc version 1.9 ======================
+API version 10
+
+upnpcommands.h:
+ added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
+
+miniupnpc.h:
+ updated macros :
+ #define MINIUPNPC_VERSION "1.9"
+ #define MINIUPNPC_API_VERSION 10
+
+====================== miniUPnPc version 1.8 ======================
+API version 9
+
+miniupnpc.h:
+ updated macros :
+ #define MINIUPNPC_VERSION "1.8"
+ #define MINIUPNPC_API_VERSION 9
+ added "unsigned int scope_id;" to struct UPNPDev
+ added scope_id argument to GetUPNPUrls()
+
+
+
+====================== miniUPnPc version 1.7 ======================
+API version 8
+
+miniupnpc.h :
+ add new macros :
+ #define MINIUPNPC_VERSION "1.7"
+ #define MINIUPNPC_API_VERSION 8
+ add rootdescURL to struct UPNPUrls
+
+
+
+====================== miniUPnPc version 1.6 ======================
+API version 8
+
+Adding support for IPv6.
+igd_desc_parse.h :
+ struct IGDdatas_service :
+ add char presentationurl[MINIUPNPC_URL_MAXSIZE];
+ struct IGDdatas :
+ add struct IGDdatas_service IPv6FC;
+miniupnpc.h :
+ new macros :
+ #define UPNPDISCOVER_SUCCESS (0)
+ #define UPNPDISCOVER_UNKNOWN_ERROR (-1)
+ #define UPNPDISCOVER_SOCKET_ERROR (-101)
+ #define UPNPDISCOVER_MEMORY_ERROR (-102)
+ simpleUPnPcommand() prototype changed (but is normaly not used by API users)
+ add arguments ipv6 and error to upnpDiscover() :
+ struct UPNPDev *
+ upnpDiscover(int delay, const char * multicastif,
+ const char * minissdpdsock, int sameport,
+ int ipv6,
+ int * error);
+ add controlURL_6FC member to struct UPNPUrls :
+ struct UPNPUrls {
+ char * controlURL;
+ char * ipcondescURL;
+ char * controlURL_CIF;
+ char * controlURL_6FC;
+ };
+
+upnpcommands.h :
+ add leaseDuration argument to UPNP_AddPortMapping()
+ add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry()
+ add UPNP_GetListOfPortMappings() function (IGDv2)
+ add IGDv2 IPv6 related functions :
+ UPNP_GetFirewallStatus()
+ UPNP_GetOutboundPinholeTimeout()
+ UPNP_AddPinhole()
+ UPNP_UpdatePinhole()
+ UPNP_DeletePinhole()
+ UPNP_CheckPinholeWorking()
+ UPNP_GetPinholePackets()
+
+
+
+====================== miniUPnPc version 1.5 ======================
+API version 5
+
+new function :
+int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
+new macro in upnpcommands.h :
+#define UPNPCOMMAND_HTTP_ERROR
+
+====================== miniUPnPc version 1.4 ======================
+Same API as version 1.3
+
+====================== miniUPnPc version 1.3 ======================
+API version 4
+
+Use UNSIGNED_INTEGER type for
+UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(),
+UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived()
+Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping()
+
+====================== miniUPnPc version 1.2 ======================
+API version 3
+
+added sameport argument to upnpDiscover()
+struct UPNPDev *
+upnpDiscover(int delay, const char * multicastif,
+ const char * minissdpdsock, int sameport);
+
+====================== miniUPnPc Version 1.1 ======================
+Same API as 1.0
+
+
+====================== miniUPnPc Version 1.0 ======================
+API version 2
+
+
+struct UPNPDev {
+ struct UPNPDev * pNext;
+ char * descURL;
+ char * st;
+ char buffer[2];
+};
+struct UPNPDev * upnpDiscover(int delay, const char * multicastif,
+ const char * minissdpdsock);
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/codelength.h b/ext/miniupnpc/codelength.h
index f5f8e30f..f5f8e30f 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/codelength.h
+++ b/ext/miniupnpc/codelength.h
diff --git a/ext/miniupnpc/connecthostport.c b/ext/miniupnpc/connecthostport.c
new file mode 100644
index 00000000..854203e0
--- /dev/null
+++ b/ext/miniupnpc/connecthostport.c
@@ -0,0 +1,266 @@
+/* $Id: connecthostport.c,v 1.15 2015/10/09 16:26:19 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2010-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution. */
+
+#define _CRT_SECURE_NO_WARNINGS
+
+/* use getaddrinfo() or gethostbyname()
+ * uncomment the following line in order to use gethostbyname() */
+#ifdef NO_GETADDRINFO
+#define USE_GETHOSTBYNAME
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#define MAXHOSTNAMELEN 64
+#define snprintf _snprintf
+#define herror
+#define socklen_t int
+#else /* #ifdef _WIN32 */
+#include <unistd.h>
+#include <sys/types.h>
+#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
+#include <sys/time.h>
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
+#include <sys/param.h>
+#include <sys/select.h>
+#include <errno.h>
+#define closesocket close
+#include <netdb.h>
+#include <netinet/in.h>
+/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
+ * during the connect() call */
+#define MINIUPNPC_IGNORE_EINTR
+#ifndef USE_GETHOSTBYNAME
+#include <sys/socket.h>
+#include <sys/select.h>
+#endif /* #ifndef USE_GETHOSTBYNAME */
+#endif /* #else _WIN32 */
+
+/* definition of PRINT_SOCKET_ERROR */
+#ifdef _WIN32
+#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
+#else
+#define PRINT_SOCKET_ERROR(x) perror(x)
+#endif
+
+#if defined(__amigaos__) || defined(__amigaos4__)
+#define herror(A) printf("%s\n", A)
+#endif
+
+#include "connecthostport.h"
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+/* connecthostport()
+ * return a socket connected (TCP) to the host and port
+ * or -1 in case of error */
+int connecthostport(const char * host, unsigned short port,
+ unsigned int scope_id)
+{
+ int s, n;
+#ifdef USE_GETHOSTBYNAME
+ struct sockaddr_in dest;
+ struct hostent *hp;
+#else /* #ifdef USE_GETHOSTBYNAME */
+ char tmp_host[MAXHOSTNAMELEN+1];
+ char port_str[8];
+ struct addrinfo *ai, *p;
+ struct addrinfo hints;
+#endif /* #ifdef USE_GETHOSTBYNAME */
+#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
+ struct timeval timeout;
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
+
+#ifdef USE_GETHOSTBYNAME
+ hp = gethostbyname(host);
+ if(hp == NULL)
+ {
+ herror(host);
+ return -1;
+ }
+ memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
+ memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
+ s = socket(PF_INET, SOCK_STREAM, 0);
+ if(s < 0)
+ {
+ PRINT_SOCKET_ERROR("socket");
+ return -1;
+ }
+#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
+ /* setting a 3 seconds timeout for the connect() call */
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+ if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt");
+ }
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+ if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt");
+ }
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
+ dest.sin_family = AF_INET;
+ dest.sin_port = htons(port);
+ n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
+#ifdef MINIUPNPC_IGNORE_EINTR
+ /* EINTR The system call was interrupted by a signal that was caught
+ * EINPROGRESS The socket is nonblocking and the connection cannot
+ * be completed immediately. */
+ while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
+ {
+ socklen_t len;
+ fd_set wset;
+ int err;
+ FD_ZERO(&wset);
+ FD_SET(s, &wset);
+ if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
+ continue;
+ /*len = 0;*/
+ /*n = getpeername(s, NULL, &len);*/
+ len = sizeof(err);
+ if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
+ PRINT_SOCKET_ERROR("getsockopt");
+ closesocket(s);
+ return -1;
+ }
+ if(err != 0) {
+ errno = err;
+ n = -1;
+ }
+ }
+#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
+ if(n<0)
+ {
+ PRINT_SOCKET_ERROR("connect");
+ closesocket(s);
+ return -1;
+ }
+#else /* #ifdef USE_GETHOSTBYNAME */
+ /* use getaddrinfo() instead of gethostbyname() */
+ memset(&hints, 0, sizeof(hints));
+ /* hints.ai_flags = AI_ADDRCONFIG; */
+#ifdef AI_NUMERICSERV
+ hints.ai_flags = AI_NUMERICSERV;
+#endif
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
+ /* hints.ai_protocol = IPPROTO_TCP; */
+ snprintf(port_str, sizeof(port_str), "%hu", port);
+ if(host[0] == '[')
+ {
+ /* literal ip v6 address */
+ int i, j;
+ for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++)
+ {
+ tmp_host[i] = host[j];
+ if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */
+ j+=2; /* skip "25" */
+ }
+ tmp_host[i] = '\0';
+ }
+ else
+ {
+ strncpy(tmp_host, host, MAXHOSTNAMELEN);
+ }
+ tmp_host[MAXHOSTNAMELEN] = '\0';
+ n = getaddrinfo(tmp_host, port_str, &hints, &ai);
+ if(n != 0)
+ {
+#ifdef _WIN32
+ fprintf(stderr, "getaddrinfo() error : %d\n", n);
+#else
+ fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
+#endif
+ return -1;
+ }
+ s = -1;
+ for(p = ai; p; p = p->ai_next)
+ {
+ s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if(s < 0)
+ continue;
+ if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) {
+ struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr;
+ addr6->sin6_scope_id = scope_id;
+ }
+#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
+ /* setting a 3 seconds timeout for the connect() call */
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+ if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt");
+ }
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+ if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt");
+ }
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
+ n = connect(s, p->ai_addr, p->ai_addrlen);
+#ifdef MINIUPNPC_IGNORE_EINTR
+ /* EINTR The system call was interrupted by a signal that was caught
+ * EINPROGRESS The socket is nonblocking and the connection cannot
+ * be completed immediately. */
+ while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
+ {
+ socklen_t len;
+ fd_set wset;
+ int err;
+ FD_ZERO(&wset);
+ FD_SET(s, &wset);
+ if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
+ continue;
+ /*len = 0;*/
+ /*n = getpeername(s, NULL, &len);*/
+ len = sizeof(err);
+ if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
+ PRINT_SOCKET_ERROR("getsockopt");
+ closesocket(s);
+ freeaddrinfo(ai);
+ return -1;
+ }
+ if(err != 0) {
+ errno = err;
+ n = -1;
+ }
+ }
+#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
+ if(n < 0)
+ {
+ closesocket(s);
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ freeaddrinfo(ai);
+ if(s < 0)
+ {
+ PRINT_SOCKET_ERROR("socket");
+ return -1;
+ }
+ if(n < 0)
+ {
+ PRINT_SOCKET_ERROR("connect");
+ return -1;
+ }
+#endif /* #ifdef USE_GETHOSTBYNAME */
+ return s;
+}
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h b/ext/miniupnpc/connecthostport.h
index 56941d6f..56941d6f 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h
+++ b/ext/miniupnpc/connecthostport.h
diff --git a/ext/miniupnpc/external-ip.sh b/ext/miniupnpc/external-ip.sh
new file mode 100755
index 00000000..965d86b2
--- /dev/null
+++ b/ext/miniupnpc/external-ip.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: external-ip.sh,v 1.1 2010/08/05 12:57:41 nanard Exp $
+# (c) 2010 Reuben Hawkins
+upnpc -s | grep ExternalIPAddress | sed 's/[^0-9\.]//g'
diff --git a/ext/miniupnpc/igd_desc_parse.c b/ext/miniupnpc/igd_desc_parse.c
new file mode 100644
index 00000000..d2999ad0
--- /dev/null
+++ b/ext/miniupnpc/igd_desc_parse.c
@@ -0,0 +1,123 @@
+/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
+/* Project : miniupnp
+ * http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution. */
+
+#include "igd_desc_parse.h"
+#include <stdio.h>
+#include <string.h>
+
+/* Start element handler :
+ * update nesting level counter and copy element name */
+void IGDstartelt(void * d, const char * name, int l)
+{
+ struct IGDdatas * datas = (struct IGDdatas *)d;
+ if(l >= MINIUPNPC_URL_MAXSIZE)
+ l = MINIUPNPC_URL_MAXSIZE-1;
+ memcpy(datas->cureltname, name, l);
+ datas->cureltname[l] = '\0';
+ datas->level++;
+ if( (l==7) && !memcmp(name, "service", l) ) {
+ datas->tmp.controlurl[0] = '\0';
+ datas->tmp.eventsuburl[0] = '\0';
+ datas->tmp.scpdurl[0] = '\0';
+ datas->tmp.servicetype[0] = '\0';
+ }
+}
+
+#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
+
+/* End element handler :
+ * update nesting level counter and update parser state if
+ * service element is parsed */
+void IGDendelt(void * d, const char * name, int l)
+{
+ struct IGDdatas * datas = (struct IGDdatas *)d;
+ datas->level--;
+ /*printf("endelt %2d %.*s\n", datas->level, l, name);*/
+ if( (l==7) && !memcmp(name, "service", l) )
+ {
+ if(COMPARE(datas->tmp.servicetype,
+ "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) {
+ memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
+ } else if(COMPARE(datas->tmp.servicetype,
+ "urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) {
+ memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
+ } else if(COMPARE(datas->tmp.servicetype,
+ "urn:schemas-upnp-org:service:WANIPConnection:")
+ || COMPARE(datas->tmp.servicetype,
+ "urn:schemas-upnp-org:service:WANPPPConnection:") ) {
+ if(datas->first.servicetype[0] == '\0') {
+ memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
+ } else {
+ memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service));
+ }
+ }
+ }
+}
+
+/* Data handler :
+ * copy data depending on the current element name and state */
+void IGDdata(void * d, const char * data, int l)
+{
+ struct IGDdatas * datas = (struct IGDdatas *)d;
+ char * dstmember = 0;
+ /*printf("%2d %s : %.*s\n",
+ datas->level, datas->cureltname, l, data); */
+ if( !strcmp(datas->cureltname, "URLBase") )
+ dstmember = datas->urlbase;
+ else if( !strcmp(datas->cureltname, "presentationURL") )
+ dstmember = datas->presentationurl;
+ else if( !strcmp(datas->cureltname, "serviceType") )
+ dstmember = datas->tmp.servicetype;
+ else if( !strcmp(datas->cureltname, "controlURL") )
+ dstmember = datas->tmp.controlurl;
+ else if( !strcmp(datas->cureltname, "eventSubURL") )
+ dstmember = datas->tmp.eventsuburl;
+ else if( !strcmp(datas->cureltname, "SCPDURL") )
+ dstmember = datas->tmp.scpdurl;
+/* else if( !strcmp(datas->cureltname, "deviceType") )
+ dstmember = datas->devicetype_tmp;*/
+ if(dstmember)
+ {
+ if(l>=MINIUPNPC_URL_MAXSIZE)
+ l = MINIUPNPC_URL_MAXSIZE-1;
+ memcpy(dstmember, data, l);
+ dstmember[l] = '\0';
+ }
+}
+
+#ifdef DEBUG
+void printIGD(struct IGDdatas * d)
+{
+ printf("urlbase = '%s'\n", d->urlbase);
+ printf("WAN Device (Common interface config) :\n");
+ /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/
+ printf(" serviceType = '%s'\n", d->CIF.servicetype);
+ printf(" controlURL = '%s'\n", d->CIF.controlurl);
+ printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl);
+ printf(" SCPDURL = '%s'\n", d->CIF.scpdurl);
+ printf("primary WAN Connection Device (IP or PPP Connection):\n");
+ /*printf(" deviceType = '%s'\n", d->first.devicetype);*/
+ printf(" servicetype = '%s'\n", d->first.servicetype);
+ printf(" controlURL = '%s'\n", d->first.controlurl);
+ printf(" eventSubURL = '%s'\n", d->first.eventsuburl);
+ printf(" SCPDURL = '%s'\n", d->first.scpdurl);
+ printf("secondary WAN Connection Device (IP or PPP Connection):\n");
+ /*printf(" deviceType = '%s'\n", d->second.devicetype);*/
+ printf(" servicetype = '%s'\n", d->second.servicetype);
+ printf(" controlURL = '%s'\n", d->second.controlurl);
+ printf(" eventSubURL = '%s'\n", d->second.eventsuburl);
+ printf(" SCPDURL = '%s'\n", d->second.scpdurl);
+ printf("WAN IPv6 Firewall Control :\n");
+ /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/
+ printf(" servicetype = '%s'\n", d->IPv6FC.servicetype);
+ printf(" controlURL = '%s'\n", d->IPv6FC.controlurl);
+ printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
+ printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
+}
+#endif /* DEBUG */
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h b/ext/miniupnpc/igd_desc_parse.h
index 0de546b6..0de546b6 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h
+++ b/ext/miniupnpc/igd_desc_parse.h
diff --git a/ext/miniupnpc/java/JavaBridgeTest.java b/ext/miniupnpc/java/JavaBridgeTest.java
new file mode 100644
index 00000000..c658c599
--- /dev/null
+++ b/ext/miniupnpc/java/JavaBridgeTest.java
@@ -0,0 +1,97 @@
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+import fr.free.miniupnp.*;
+
+/**
+ *
+ * @author syuu
+ */
+public class JavaBridgeTest {
+ public static void main(String[] args) {
+ int UPNP_DELAY = 2000;
+ MiniupnpcLibrary miniupnpc = MiniupnpcLibrary.INSTANCE;
+ UPNPDev devlist = null;
+ UPNPUrls urls = new UPNPUrls();
+ IGDdatas data = new IGDdatas();
+ ByteBuffer lanaddr = ByteBuffer.allocate(16);
+ ByteBuffer intClient = ByteBuffer.allocate(16);
+ ByteBuffer intPort = ByteBuffer.allocate(6);
+ ByteBuffer desc = ByteBuffer.allocate(80);
+ ByteBuffer enabled = ByteBuffer.allocate(4);
+ ByteBuffer leaseDuration = ByteBuffer.allocate(16);
+ int ret;
+ int i;
+
+ if(args.length < 2) {
+ System.err.println("Usage : java [...] JavaBridgeTest port protocol");
+ System.out.println(" port is numeric, protocol is TCP or UDP");
+ return;
+ }
+
+ devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, (byte)2, IntBuffer.allocate(1));
+ if (devlist != null) {
+ System.out.println("List of UPNP devices found on the network :");
+ for (UPNPDev device = devlist; device != null; device = device.pNext) {
+ System.out.println("desc: " + device.descURL.getString(0) + " st: " + device.st.getString(0));
+ }
+ if ((i = miniupnpc.UPNP_GetValidIGD(devlist, urls, data, lanaddr, 16)) != 0) {
+ switch (i) {
+ case 1:
+ System.out.println("Found valid IGD : " + urls.controlURL.getString(0));
+ break;
+ case 2:
+ System.out.println("Found a (not connected?) IGD : " + urls.controlURL.getString(0));
+ System.out.println("Trying to continue anyway");
+ break;
+ case 3:
+ System.out.println("UPnP device found. Is it an IGD ? : " + urls.controlURL.getString(0));
+ System.out.println("Trying to continue anyway");
+ break;
+ default:
+ System.out.println("Found device (igd ?) : " + urls.controlURL.getString(0));
+ System.out.println("Trying to continue anyway");
+
+ }
+ System.out.println("Local LAN ip address : " + new String(lanaddr.array()));
+ ByteBuffer externalAddress = ByteBuffer.allocate(16);
+ miniupnpc.UPNP_GetExternalIPAddress(urls.controlURL.getString(0),
+ new String(data.first.servicetype), externalAddress);
+ System.out.println("ExternalIPAddress = " + new String(externalAddress.array()));
+ ret = miniupnpc.UPNP_AddPortMapping(
+ urls.controlURL.getString(0), // controlURL
+ new String(data.first.servicetype), // servicetype
+ args[0], // external Port
+ args[0], // internal Port
+ new String(lanaddr.array()), // internal client
+ "added via miniupnpc/JAVA !", // description
+ args[1], // protocol UDP or TCP
+ null, // remote host (useless)
+ "0"); // leaseDuration
+ if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
+ System.out.println("AddPortMapping() failed with code " + ret);
+ ret = miniupnpc.UPNP_GetSpecificPortMappingEntry(
+ urls.controlURL.getString(0), new String(data.first.servicetype),
+ args[0], args[1], null, intClient, intPort,
+ desc, enabled, leaseDuration);
+ if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
+ System.out.println("GetSpecificPortMappingEntry() failed with code " + ret);
+ System.out.println("InternalIP:Port = " +
+ new String(intClient.array()) + ":" + new String(intPort.array()) +
+ " (" + new String(desc.array()) + ")");
+ ret = miniupnpc.UPNP_DeletePortMapping(
+ urls.controlURL.getString(0),
+ new String(data.first.servicetype),
+ args[0], args[1], null);
+ if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
+ System.out.println("DelPortMapping() failed with code " + ret);
+ miniupnpc.FreeUPNPUrls(urls);
+ } else {
+ System.out.println("No valid UPNP Internet Gateway Device found.");
+ }
+ miniupnpc.freeUPNPDevlist(devlist);
+ } else {
+ System.out.println("No IGD UPnP Device found on the network !\n");
+ }
+ }
+}
diff --git a/ext/miniupnpc/java/testjava.bat b/ext/miniupnpc/java/testjava.bat
new file mode 100755
index 00000000..b836da14
--- /dev/null
+++ b/ext/miniupnpc/java/testjava.bat
@@ -0,0 +1,8 @@
+@echo off
+set JAVA=java
+set JAVAC=javac
+REM notice the semicolon for Windows. Write once, run ... oh nevermind
+set CP=miniupnpc_win32.jar;.
+
+%JAVAC% -cp "%CP%" JavaBridgeTest.java || exit 1
+%JAVA% -cp "%CP%" JavaBridgeTest 12345 UDP || exit 1
diff --git a/ext/miniupnpc/java/testjava.sh b/ext/miniupnpc/java/testjava.sh
new file mode 100755
index 00000000..9880523a
--- /dev/null
+++ b/ext/miniupnpc/java/testjava.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+JAVA=java
+JAVAC=javac
+CP=$(for i in *.jar; do echo -n $i:; done).
+
+$JAVAC -cp $CP JavaBridgeTest.java || exit 1
+$JAVA -cp $CP JavaBridgeTest 12345 UDP || exit 1
diff --git a/ext/miniupnpc/listdevices.c b/ext/miniupnpc/listdevices.c
new file mode 100644
index 00000000..a93c29ff
--- /dev/null
+++ b/ext/miniupnpc/listdevices.c
@@ -0,0 +1,110 @@
+/* $Id: listdevices.c,v 1.7 2015/10/08 16:15:47 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2013-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#endif /* _WIN32 */
+#include "miniupnpc.h"
+
+int main(int argc, char * * argv)
+{
+ const char * searched_device = NULL;
+ const char * * searched_devices = NULL;
+ const char * multicastif = 0;
+ const char * minissdpdpath = 0;
+ int ipv6 = 0;
+ unsigned char ttl = 2;
+ int error = 0;
+ struct UPNPDev * devlist = 0;
+ struct UPNPDev * dev;
+ int i;
+
+#ifdef _WIN32
+ WSADATA wsaData;
+ int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
+ if(nResult != NO_ERROR)
+ {
+ fprintf(stderr, "WSAStartup() failed.\n");
+ return -1;
+ }
+#endif
+
+ for(i = 1; i < argc; i++) {
+ if(strcmp(argv[i], "-6") == 0)
+ ipv6 = 1;
+ else if(strcmp(argv[i], "-d") == 0) {
+ if(++i >= argc) {
+ fprintf(stderr, "%s option needs one argument\n", "-d");
+ return 1;
+ }
+ searched_device = argv[i];
+ } else if(strcmp(argv[i], "-t") == 0) {
+ if(++i >= argc) {
+ fprintf(stderr, "%s option needs one argument\n", "-t");
+ return 1;
+ }
+ ttl = (unsigned char)atoi(argv[i]);
+ } else if(strcmp(argv[i], "-l") == 0) {
+ if(++i >= argc) {
+ fprintf(stderr, "-l option needs at least one argument\n");
+ return 1;
+ }
+ searched_devices = (const char * *)(argv + i);
+ break;
+ } else if(strcmp(argv[i], "-m") == 0) {
+ if(++i >= argc) {
+ fprintf(stderr, "-m option needs one argument\n");
+ return 1;
+ }
+ multicastif = argv[i];
+ } else {
+ printf("usage : %s [options] [-l <device1> <device2> ...]\n", argv[0]);
+ printf("options :\n");
+ printf(" -6 : use IPv6\n");
+ printf(" -m address/ifname : network interface to use for multicast\n");
+ printf(" -d <device string> : search only for this type of device\n");
+ printf(" -l <device1> <device2> ... : search only for theses types of device\n");
+ printf(" -t ttl : set multicast TTL. Default value is 2.\n");
+ printf(" -h : this help\n");
+ return 1;
+ }
+ }
+
+ if(searched_device) {
+ printf("searching UPnP device type %s\n", searched_device);
+ devlist = upnpDiscoverDevice(searched_device,
+ 2000, multicastif, minissdpdpath,
+ 0/*localport*/, ipv6, ttl, &error);
+ } else if(searched_devices) {
+ printf("searching UPnP device types :\n");
+ for(i = 0; searched_devices[i]; i++)
+ printf("\t%s\n", searched_devices[i]);
+ devlist = upnpDiscoverDevices(searched_devices,
+ 2000, multicastif, minissdpdpath,
+ 0/*localport*/, ipv6, ttl, &error, 1);
+ } else {
+ printf("searching all UPnP devices\n");
+ devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath,
+ 0/*localport*/, ipv6, ttl, &error);
+ }
+ if(devlist) {
+ for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) {
+ printf("%3d: %-48s\n", i, dev->st);
+ printf(" %s\n", dev->descURL);
+ printf(" %s\n", dev->usn);
+ }
+ freeUPNPDevlist(devlist);
+ } else {
+ printf("no device found.\n");
+ }
+
+ return 0;
+}
+
diff --git a/ext/miniupnpc/man3/miniupnpc.3 b/ext/miniupnpc/man3/miniupnpc.3
new file mode 100644
index 00000000..7b997d47
--- /dev/null
+++ b/ext/miniupnpc/man3/miniupnpc.3
@@ -0,0 +1,55 @@
+.TH MINIUPNPC 3
+.SH NAME
+miniupnpc \- UPnP client library
+.SH SYNOPSIS
+.SH DESCRIPTION
+The miniupnpc library implement the UPnP protocol defined
+to dialog with Internet Gateway Devices. It also has
+the ability to use data gathered by minissdpd(1) about
+UPnP devices up on the network in order to skip the
+long UPnP device discovery process.
+.PP
+At first, upnpDiscover(3) has to be used to discover UPnP IGD present
+on the network. Then UPNP_GetValidIGD(3) to select the right one.
+Alternatively, UPNP_GetIGDFromUrl(3) could be used to bypass discovery
+process if the root description url of the device to use is known.
+Then all the UPNP_* functions can be used, such as
+UPNP_GetConnectionTypeInfo(3), UPNP_AddPortMapping(3), etc...
+.SH "HEADER FILES"
+.IP miniupnpc.h
+That's the main header file for the miniupnpc library API.
+It contains all the functions and structures related to device discovery.
+.IP upnpcommands.h
+This header file contain the UPnP IGD methods that are accessible
+through the miniupnpc API. The name of the C functions are matching
+the UPnP methods names. ie: GetGenericPortMappingEntry is
+UPNP_GetGenericPortMappingEntry.
+.SH "API FUNCTIONS"
+.IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int localport, int ipv6, int * error);"
+execute the discovery process.
+delay (in millisecond) is the maximum time for waiting any device response.
+If available, device list will be obtained from MiniSSDPd.
+Default path for minissdpd socket will be used if minissdpdsock argument is NULL.
+If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets.
+If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
+from the source port 1900 (same as destination port), if set to
+UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
+be attempted as the source port.
+If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process.
+.IP "void freeUPNPDevlist(struct UPNPDev * devlist);"
+free the list returned by upnpDiscover().
+.IP "int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);"
+browse the list of device returned by upnpDiscover(), find
+a live UPnP internet gateway device and fill structures passed as arguments
+with data used for UPNP methods invokation.
+.IP "int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);"
+permit to bypass the upnpDiscover() call if the xml root description
+URL of the UPnP IGD is known.
+Fill structures passed as arguments
+with data used for UPNP methods invokation.
+.IP "void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *);"
+.IP "void FreeUPNPUrls(struct UPNPUrls *);"
+
+.SH "SEE ALSO"
+minissdpd(1)
+.SH BUGS
diff --git a/ext/miniupnpc/mingw32make.bat b/ext/miniupnpc/mingw32make.bat
new file mode 100644
index 00000000..c5d3cc4f
--- /dev/null
+++ b/ext/miniupnpc/mingw32make.bat
@@ -0,0 +1,8 @@
+@mingw32-make -f Makefile.mingw %1
+@if errorlevel 1 goto end
+@if not exist upnpc-static.exe goto end
+@strip upnpc-static.exe
+@upx --best upnpc-static.exe
+@strip upnpc-shared.exe
+@upx --best upnpc-shared.exe
+:end
diff --git a/ext/miniupnpc/minihttptestserver.c b/ext/miniupnpc/minihttptestserver.c
new file mode 100644
index 00000000..32e3cb78
--- /dev/null
+++ b/ext/miniupnpc/minihttptestserver.c
@@ -0,0 +1,655 @@
+/* $Id: minihttptestserver.c,v 1.18 2015/07/15 12:41:15 nanard Exp $ */
+/* Project : miniUPnP
+ * Author : Thomas Bernard
+ * Copyright (c) 2011-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+
+#define CRAP_LENGTH (2048)
+
+volatile sig_atomic_t quit = 0;
+volatile sig_atomic_t child_to_wait_for = 0;
+
+/**
+ * signal handler for SIGCHLD (child status has changed)
+ */
+void handle_signal_chld(int sig)
+{
+ (void)sig;
+ /* printf("handle_signal_chld(%d)\n", sig); */
+ ++child_to_wait_for;
+}
+
+/**
+ * signal handler for SIGINT (CRTL C)
+ */
+void handle_signal_int(int sig)
+{
+ (void)sig;
+ /* printf("handle_signal_int(%d)\n", sig); */
+ quit = 1;
+}
+
+/**
+ * build a text/plain content of the specified length
+ */
+void build_content(char * p, int n)
+{
+ char line_buffer[80];
+ int k;
+ int i = 0;
+
+ while(n > 0) {
+ k = snprintf(line_buffer, sizeof(line_buffer),
+ "%04d_ABCDEFGHIJKL_This_line_is_64_bytes_long_ABCDEFGHIJKL_%04d\r\n",
+ i, i);
+ if(k != 64) {
+ fprintf(stderr, "snprintf() returned %d in build_content()\n", k);
+ }
+ ++i;
+ if(n >= 64) {
+ memcpy(p, line_buffer, 64);
+ p += 64;
+ n -= 64;
+ } else {
+ memcpy(p, line_buffer, n);
+ p += n;
+ n = 0;
+ }
+ }
+}
+
+/**
+ * build crappy content
+ */
+void build_crap(char * p, int n)
+{
+ static const char crap[] = "_CRAP_\r\n";
+ int i;
+
+ while(n > 0) {
+ i = sizeof(crap) - 1;
+ if(i > n)
+ i = n;
+ memcpy(p, crap, i);
+ p += i;
+ n -= i;
+ }
+}
+
+/**
+ * build chunked response.
+ * return a malloc'ed buffer
+ */
+char * build_chunked_response(int content_length, int * response_len)
+{
+ char * response_buffer;
+ char * content_buffer;
+ int buffer_length;
+ int i, n;
+
+ /* allocate to have some margin */
+ buffer_length = 256 + content_length + (content_length >> 4);
+ response_buffer = malloc(buffer_length);
+ if(response_buffer == NULL)
+ return NULL;
+ *response_len = snprintf(response_buffer, buffer_length,
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n");
+
+ /* build the content */
+ content_buffer = malloc(content_length);
+ if(content_buffer == NULL) {
+ free(response_buffer);
+ return NULL;
+ }
+ build_content(content_buffer, content_length);
+
+ /* chunk it */
+ i = 0;
+ while(i < content_length) {
+ n = (rand() % 199) + 1;
+ if(i + n > content_length) {
+ n = content_length - i;
+ }
+ /* TODO : check buffer size ! */
+ *response_len += snprintf(response_buffer + *response_len,
+ buffer_length - *response_len,
+ "%x\r\n", n);
+ memcpy(response_buffer + *response_len, content_buffer + i, n);
+ *response_len += n;
+ i += n;
+ response_buffer[(*response_len)++] = '\r';
+ response_buffer[(*response_len)++] = '\n';
+ }
+ /* the last chunk : "0\r\n" a empty body and then
+ * the final "\r\n" */
+ memcpy(response_buffer + *response_len, "0\r\n\r\n", 5);
+ *response_len += 5;
+ free(content_buffer);
+
+ printf("resp_length=%d buffer_length=%d content_length=%d\n",
+ *response_len, buffer_length, content_length);
+ return response_buffer;
+}
+
+/* favicon.ico generator */
+#ifdef OLD_HEADER
+#define FAVICON_LENGTH (6 + 16 + 12 + 8 + 32 * 4)
+#else
+#define FAVICON_LENGTH (6 + 16 + 40 + 8 + 32 * 4)
+#endif
+void build_favicon_content(char * p, int n)
+{
+ int i;
+ if(n < FAVICON_LENGTH)
+ return;
+ /* header : 6 bytes */
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 1; /* type : ICO */
+ *p++ = 0;
+ *p++ = 1; /* number of images in file */
+ *p++ = 0;
+ /* image directory (1 entry) : 16 bytes */
+ *p++ = 16; /* width */
+ *p++ = 16; /* height */
+ *p++ = 2; /* number of colors in the palette. 0 = no palette */
+ *p++ = 0; /* reserved */
+ *p++ = 1; /* color planes */
+ *p++ = 0; /* " */
+ *p++ = 1; /* bpp */
+ *p++ = 0; /* " */
+#ifdef OLD_HEADER
+ *p++ = 12 + 8 + 32 * 4; /* bmp size */
+#else
+ *p++ = 40 + 8 + 32 * 4; /* bmp size */
+#endif
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 6 + 16; /* bmp offset */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ /* BMP */
+#ifdef OLD_HEADER
+ /* BITMAPCOREHEADER */
+ *p++ = 12; /* size of this header */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 16; /* width */
+ *p++ = 0; /* " */
+ *p++ = 16 * 2; /* height x 2 ! */
+ *p++ = 0; /* " */
+ *p++ = 1; /* color planes */
+ *p++ = 0; /* " */
+ *p++ = 1; /* bpp */
+ *p++ = 0; /* " */
+#else
+ /* BITMAPINFOHEADER */
+ *p++ = 40; /* size of this header */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 16; /* width */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 16 * 2; /* height x 2 ! */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 0; /* " */
+ *p++ = 1; /* color planes */
+ *p++ = 0; /* " */
+ *p++ = 1; /* bpp */
+ *p++ = 0; /* " */
+ /* compression method, image size, ppm x, ppm y */
+ /* colors in the palette ? */
+ /* important colors */
+ for(i = 4 * 6; i > 0; --i)
+ *p++ = 0;
+#endif
+ /* palette */
+ *p++ = 0; /* b */
+ *p++ = 0; /* g */
+ *p++ = 0; /* r */
+ *p++ = 0; /* reserved */
+ *p++ = 255; /* b */
+ *p++ = 255; /* g */
+ *p++ = 255; /* r */
+ *p++ = 0; /* reserved */
+ /* pixel data */
+ for(i = 16; i > 0; --i) {
+ if(i & 1) {
+ *p++ = 0125;
+ *p++ = 0125;
+ } else {
+ *p++ = 0252;
+ *p++ = 0252;
+ }
+ *p++ = 0;
+ *p++ = 0;
+ }
+ /* Opacity MASK */
+ for(i = 16 * 4; i > 0; --i) {
+ *p++ = 0;
+ }
+}
+
+enum modes {
+ MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL, MODE_FAVICON
+};
+
+const struct {
+ const enum modes mode;
+ const char * text;
+} modes_array[] = {
+ {MODE_CHUNKED, "chunked"},
+ {MODE_ADDCRAP, "addcrap"},
+ {MODE_NORMAL, "normal"},
+ {MODE_FAVICON, "favicon.ico"},
+ {MODE_INVALID, NULL}
+};
+
+/**
+ * write the response with random behaviour !
+ */
+void send_response(int c, const char * buffer, int len)
+{
+ int n;
+ while(len > 0) {
+ n = (rand() % 99) + 1;
+ if(n > len)
+ n = len;
+ n = write(c, buffer, n);
+ if(n < 0) {
+ if(errno != EINTR) {
+ perror("write");
+ return;
+ }
+ /* if errno == EINTR, try again */
+ } else {
+ len -= n;
+ buffer += n;
+ }
+ usleep(10000); /* 10ms */
+ }
+}
+
+/**
+ * handle the HTTP connection
+ */
+void handle_http_connection(int c)
+{
+ char request_buffer[2048];
+ int request_len = 0;
+ int headers_found = 0;
+ int n, i;
+ char request_method[16];
+ char request_uri[256];
+ char http_version[16];
+ char * p;
+ char * response_buffer;
+ int response_len;
+ enum modes mode;
+ int content_length = 16*1024;
+
+ /* read the request */
+ while(request_len < (int)sizeof(request_buffer) && !headers_found) {
+ n = read(c,
+ request_buffer + request_len,
+ sizeof(request_buffer) - request_len);
+ if(n < 0) {
+ if(errno == EINTR)
+ continue;
+ perror("read");
+ return;
+ } else if(n==0) {
+ /* remote host closed the connection */
+ break;
+ } else {
+ request_len += n;
+ for(i = 0; i < request_len - 3; i++) {
+ if(0 == memcmp(request_buffer + i, "\r\n\r\n", 4)) {
+ /* found the end of headers */
+ headers_found = 1;
+ break;
+ }
+ }
+ }
+ }
+ if(!headers_found) {
+ /* error */
+ printf("no HTTP header found in the request\n");
+ return;
+ }
+ printf("headers :\n%.*s", request_len, request_buffer);
+ /* the request have been received, now parse the request line */
+ p = request_buffer;
+ for(i = 0; i < (int)sizeof(request_method) - 1; i++) {
+ if(*p == ' ' || *p == '\r')
+ break;
+ request_method[i] = *p;
+ ++p;
+ }
+ request_method[i] = '\0';
+ while(*p == ' ')
+ p++;
+ for(i = 0; i < (int)sizeof(request_uri) - 1; i++) {
+ if(*p == ' ' || *p == '\r')
+ break;
+ request_uri[i] = *p;
+ ++p;
+ }
+ request_uri[i] = '\0';
+ while(*p == ' ')
+ p++;
+ for(i = 0; i < (int)sizeof(http_version) - 1; i++) {
+ if(*p == ' ' || *p == '\r')
+ break;
+ http_version[i] = *p;
+ ++p;
+ }
+ http_version[i] = '\0';
+ printf("Method = %s, URI = %s, %s\n",
+ request_method, request_uri, http_version);
+ /* check if the request method is allowed */
+ if(0 != strcmp(request_method, "GET")) {
+ const char response405[] = "HTTP/1.1 405 Method Not Allowed\r\n"
+ "Allow: GET\r\n\r\n";
+ const char * pc;
+ /* 405 Method Not Allowed */
+ /* The response MUST include an Allow header containing a list
+ * of valid methods for the requested resource. */
+ n = sizeof(response405) - 1;
+ pc = response405;
+ while(n > 0) {
+ i = write(c, pc, n);
+ if(i<0) {
+ if(errno != EINTR) {
+ perror("write");
+ return;
+ }
+ } else {
+ n -= i;
+ pc += i;
+ }
+ }
+ return;
+ }
+
+ mode = MODE_INVALID;
+ /* use the request URI to know what to do */
+ for(i = 0; modes_array[i].mode != MODE_INVALID; i++) {
+ if(strstr(request_uri, modes_array[i].text)) {
+ mode = modes_array[i].mode; /* found */
+ break;
+ }
+ }
+
+ switch(mode) {
+ case MODE_CHUNKED:
+ response_buffer = build_chunked_response(content_length, &response_len);
+ break;
+ case MODE_ADDCRAP:
+ response_len = content_length+256;
+ response_buffer = malloc(response_len);
+ if(!response_buffer)
+ break;
+ n = snprintf(response_buffer, response_len,
+ "HTTP/1.1 200 OK\r\n"
+ "Server: minihttptestserver\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: %d\r\n"
+ "\r\n", content_length);
+ response_len = content_length+n+CRAP_LENGTH;
+ p = realloc(response_buffer, response_len);
+ if(p == NULL) {
+ /* error 500 */
+ free(response_buffer);
+ response_buffer = NULL;
+ break;
+ }
+ response_buffer = p;
+ build_content(response_buffer + n, content_length);
+ build_crap(response_buffer + n + content_length, CRAP_LENGTH);
+ break;
+ case MODE_FAVICON:
+ content_length = FAVICON_LENGTH;
+ response_len = content_length + 256;
+ response_buffer = malloc(response_len);
+ if(!response_buffer)
+ break;
+ n = snprintf(response_buffer, response_len,
+ "HTTP/1.1 200 OK\r\n"
+ "Server: minihttptestserver\r\n"
+ "Content-Type: image/vnd.microsoft.icon\r\n"
+ "Content-Length: %d\r\n"
+ "\r\n", content_length);
+ /* image/x-icon */
+ build_favicon_content(response_buffer + n, content_length);
+ response_len = content_length + n;
+ break;
+ default:
+ response_len = content_length+256;
+ response_buffer = malloc(response_len);
+ if(!response_buffer)
+ break;
+ n = snprintf(response_buffer, response_len,
+ "HTTP/1.1 200 OK\r\n"
+ "Server: minihttptestserver\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n");
+ response_len = content_length+n;
+ p = realloc(response_buffer, response_len);
+ if(p == NULL) {
+ /* Error 500 */
+ free(response_buffer);
+ response_buffer = NULL;
+ break;
+ }
+ response_buffer = p;
+ build_content(response_buffer + n, response_len - n);
+ }
+
+ if(response_buffer) {
+ send_response(c, response_buffer, response_len);
+ free(response_buffer);
+ } else {
+ /* Error 500 */
+ }
+}
+
+/**
+ */
+int main(int argc, char * * argv) {
+ int ipv6 = 0;
+ int s, c, i;
+ unsigned short port = 0;
+ struct sockaddr_storage server_addr;
+ socklen_t server_addrlen;
+ struct sockaddr_storage client_addr;
+ socklen_t client_addrlen;
+ pid_t pid;
+ int child = 0;
+ int status;
+ const char * expected_file_name = NULL;
+ struct sigaction sa;
+
+ for(i = 1; i < argc; i++) {
+ if(argv[i][0] == '-') {
+ switch(argv[i][1]) {
+ case '6':
+ ipv6 = 1;
+ break;
+ case 'e':
+ /* write expected file ! */
+ expected_file_name = argv[++i];
+ break;
+ case 'p':
+ /* port */
+ if(++i < argc) {
+ port = (unsigned short)atoi(argv[i]);
+ }
+ break;
+ default:
+ fprintf(stderr, "unknown command line switch '%s'\n", argv[i]);
+ }
+ } else {
+ fprintf(stderr, "unkown command line argument '%s'\n", argv[i]);
+ }
+ }
+
+ srand(time(NULL));
+
+ memset(&sa, 0, sizeof(struct sigaction));
+
+ /*signal(SIGCHLD, handle_signal_chld);*/
+ sa.sa_handler = handle_signal_chld;
+ if(sigaction(SIGCHLD, &sa, NULL) < 0) {
+ perror("sigaction");
+ return 1;
+ }
+ /*signal(SIGINT, handle_signal_int);*/
+ sa.sa_handler = handle_signal_int;
+ if(sigaction(SIGINT, &sa, NULL) < 0) {
+ perror("sigaction");
+ return 1;
+ }
+
+ s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
+ if(s < 0) {
+ perror("socket");
+ return 1;
+ }
+ memset(&server_addr, 0, sizeof(struct sockaddr_storage));
+ memset(&client_addr, 0, sizeof(struct sockaddr_storage));
+ if(ipv6) {
+ struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr;
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons(port);
+ addr->sin6_addr = in6addr_loopback;
+ } else {
+ struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr;
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(port);
+ addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ }
+ if(bind(s, (struct sockaddr *)&server_addr,
+ ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0) {
+ perror("bind");
+ return 1;
+ }
+ if(listen(s, 5) < 0) {
+ perror("listen");
+ }
+ if(port == 0) {
+ server_addrlen = sizeof(struct sockaddr_storage);
+ if(getsockname(s, (struct sockaddr *)&server_addr, &server_addrlen) < 0) {
+ perror("getsockname");
+ return 1;
+ }
+ if(ipv6) {
+ struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr;
+ port = ntohs(addr->sin6_port);
+ } else {
+ struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr;
+ port = ntohs(addr->sin_port);
+ }
+ printf("Listening on port %hu\n", port);
+ fflush(stdout);
+ }
+
+ /* write expected file */
+ if(expected_file_name) {
+ FILE * f;
+ f = fopen(expected_file_name, "wb");
+ if(f) {
+ char * buffer;
+ buffer = malloc(16*1024);
+ if(buffer == NULL) {
+ fprintf(stderr, "memory allocation error\n");
+ } else {
+ build_content(buffer, 16*1024);
+ i = fwrite(buffer, 1, 16*1024, f);
+ if(i != 16*1024) {
+ fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024);
+ }
+ free(buffer);
+ }
+ fclose(f);
+ } else {
+ fprintf(stderr, "error opening file %s for writing\n", expected_file_name);
+ }
+ }
+
+ /* fork() loop */
+ while(!child && !quit) {
+ while(child_to_wait_for > 0) {
+ pid = wait(&status);
+ if(pid < 0) {
+ perror("wait");
+ } else {
+ printf("child(%d) terminated with status %d\n", pid, status);
+ }
+ --child_to_wait_for;
+ }
+ client_addrlen = sizeof(struct sockaddr_storage);
+ c = accept(s, (struct sockaddr *)&client_addr,
+ &client_addrlen);
+ if(c < 0) {
+ if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+ continue;
+ perror("accept");
+ return 1;
+ }
+ printf("accept...\n");
+ pid = fork();
+ if(pid < 0) {
+ perror("fork");
+ return 1;
+ } else if(pid == 0) {
+ /* child */
+ child = 1;
+ close(s);
+ s = -1;
+ handle_http_connection(c);
+ }
+ close(c);
+ }
+ if(s >= 0) {
+ close(s);
+ s = -1;
+ }
+ if(!child) {
+ while(child_to_wait_for > 0) {
+ pid = wait(&status);
+ if(pid < 0) {
+ perror("wait");
+ } else {
+ printf("child(%d) terminated with status %d\n", pid, status);
+ }
+ --child_to_wait_for;
+ }
+ printf("Bye...\n");
+ }
+ return 0;
+}
+
diff --git a/ext/miniupnpc/minisoap.c b/ext/miniupnpc/minisoap.c
new file mode 100644
index 00000000..478bce6b
--- /dev/null
+++ b/ext/miniupnpc/minisoap.c
@@ -0,0 +1,130 @@
+#define _CRT_SECURE_NO_WARNINGS
+/* $Id: minisoap.c,v 1.24 2015/10/26 17:05:07 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ *
+ * Minimal SOAP implementation for UPnP protocol.
+ */
+#include <stdio.h>
+#include <string.h>
+#ifdef _WIN32
+#include <io.h>
+#include <winsock2.h>
+#define snprintf _snprintf
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+#include "minisoap.h"
+#ifdef _WIN32
+#define OS_STRING "Win32"
+#define MINIUPNPC_VERSION_STRING "1.9"
+#define UPNP_VERSION_STRING "UPnP/1.1"
+#else
+#include "miniupnpcstrings.h"
+#endif
+
+/* only for malloc */
+#include <stdlib.h>
+
+#ifdef _WIN32
+#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
+#else
+#define PRINT_SOCKET_ERROR(x) perror(x)
+#endif
+
+/* httpWrite sends the headers and the body to the socket
+ * and returns the number of bytes sent */
+static int
+httpWrite(int fd, const char * body, int bodysize,
+ const char * headers, int headerssize)
+{
+ int n = 0;
+ /*n = write(fd, headers, headerssize);*/
+ /*if(bodysize>0)
+ n += write(fd, body, bodysize);*/
+ /* Note : my old linksys router only took into account
+ * soap request that are sent into only one packet */
+ char * p;
+ /* TODO: AVOID MALLOC, we could use writev() for that */
+ p = malloc(headerssize+bodysize);
+ if(!p)
+ return -1;
+ memcpy(p, headers, headerssize);
+ memcpy(p+headerssize, body, bodysize);
+ /*n = write(fd, p, headerssize+bodysize);*/
+ n = send(fd, p, headerssize+bodysize, 0);
+ if(n<0) {
+ PRINT_SOCKET_ERROR("send");
+ }
+ /* disable send on the socket */
+ /* draytek routers dont seems to like that... */
+#if 0
+#ifdef _WIN32
+ if(shutdown(fd, SD_SEND)<0) {
+#else
+ if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/
+#endif
+ PRINT_SOCKET_ERROR("shutdown");
+ }
+#endif
+ free(p);
+ return n;
+}
+
+/* self explanatory */
+int soapPostSubmit(int fd,
+ const char * url,
+ const char * host,
+ unsigned short port,
+ const char * action,
+ const char * body,
+ const char * httpversion)
+{
+ int bodysize;
+ char headerbuf[512];
+ int headerssize;
+ char portstr[8];
+ bodysize = (int)strlen(body);
+ /* We are not using keep-alive HTTP connections.
+ * HTTP/1.1 needs the header Connection: close to do that.
+ * This is the default with HTTP/1.0
+ * Using HTTP/1.1 means we need to support chunked transfer-encoding :
+ * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked
+ * transfer encoding. */
+ /* Connection: Close is normally there only in HTTP/1.1 but who knows */
+ portstr[0] = '\0';
+ if(port != 80)
+ snprintf(portstr, sizeof(portstr), ":%hu", port);
+ headerssize = snprintf(headerbuf, sizeof(headerbuf),
+ "POST %s HTTP/%s\r\n"
+ "Host: %s%s\r\n"
+ "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
+ "Content-Length: %d\r\n"
+ "Content-Type: text/xml\r\n"
+ "SOAPAction: \"%s\"\r\n"
+ "Connection: Close\r\n"
+ "Cache-Control: no-cache\r\n" /* ??? */
+ "Pragma: no-cache\r\n"
+ "\r\n",
+ url, httpversion, host, portstr, bodysize, action);
+ if ((unsigned int)headerssize >= sizeof(headerbuf))
+ return -1;
+#ifdef DEBUG
+ /*printf("SOAP request : headersize=%d bodysize=%d\n",
+ headerssize, bodysize);
+ */
+ printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n",
+ url, httpversion, host, portstr);
+ printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize);
+ printf("Headers :\n%s", headerbuf);
+ printf("Body :\n%s\n", body);
+#endif
+ return httpWrite(fd, body, bodysize, headerbuf, headerssize);
+}
+
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/minisoap.h b/ext/miniupnpc/minisoap.h
index 14c859d1..14c859d1 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/minisoap.h
+++ b/ext/miniupnpc/minisoap.h
diff --git a/ext/miniupnpc/minissdpc.c b/ext/miniupnpc/minissdpc.c
new file mode 100644
index 00000000..a371d161
--- /dev/null
+++ b/ext/miniupnpc/minissdpc.c
@@ -0,0 +1,851 @@
+#define _CRT_SECURE_NO_WARNINGS
+
+/* $Id: minissdpc.c,v 1.30 2015/10/26 17:05:07 nanard Exp $ */
+/* Project : miniupnp
+ * Web : http://miniupnp.free.fr/
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENCE file. */
+/*#include <syslog.h>*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#include <iphlpapi.h>
+#include <winsock.h>
+#define snprintf _snprintf
+#if !defined(_MSC_VER)
+#include <stdint.h>
+#else /* !defined(_MSC_VER) */
+typedef unsigned short uint16_t;
+#endif /* !defined(_MSC_VER) */
+#ifndef strncasecmp
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define strncasecmp _memicmp
+#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
+#define strncasecmp memicmp
+#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
+#endif /* #ifndef strncasecmp */
+#endif /* _WIN32 */
+#if defined(__amigaos__) || defined(__amigaos4__)
+#include <sys/socket.h>
+#endif /* defined(__amigaos__) || defined(__amigaos4__) */
+#if defined(__amigaos__)
+#define uint16_t unsigned short
+#endif /* defined(__amigaos__) */
+/* Hack */
+#define UNIX_PATH_LEN 108
+struct sockaddr_un {
+ uint16_t sun_family;
+ char sun_path[UNIX_PATH_LEN];
+};
+#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
+#include <strings.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#define closesocket close
+#endif
+
+#ifdef _WIN32
+#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
+#else
+#define PRINT_SOCKET_ERROR(x) perror(x)
+#endif
+
+#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
+#define HAS_IP_MREQN
+#endif
+
+#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
+/* Several versions of glibc don't define this structure,
+ * define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
+struct ip_mreqn
+{
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_address; /* local IP address of interface */
+ int imr_ifindex; /* Interface index */
+};
+#endif
+
+#if defined(__amigaos__) || defined(__amigaos4__)
+/* Amiga OS specific stuff */
+#define TIMEVAL struct timeval
+#endif
+
+#include "minissdpc.h"
+#include "miniupnpc.h"
+#include "receivedata.h"
+
+#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
+
+#include "codelength.h"
+
+struct UPNPDev *
+getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
+{
+ struct UPNPDev * devlist = NULL;
+ int s;
+ int res;
+
+ s = connectToMiniSSDPD(socketpath);
+ if (s < 0) {
+ if (error)
+ *error = s;
+ return NULL;
+ }
+ res = requestDevicesFromMiniSSDPD(s, devtype);
+ if (res < 0) {
+ if (error)
+ *error = res;
+ } else {
+ devlist = receiveDevicesFromMiniSSDPD(s, error);
+ }
+ disconnectFromMiniSSDPD(s);
+ return devlist;
+}
+
+/* macros used to read from unix socket */
+#define READ_BYTE_BUFFER(c) \
+ if((int)bufferindex >= n) { \
+ n = read(s, buffer, sizeof(buffer)); \
+ if(n<=0) break; \
+ bufferindex = 0; \
+ } \
+ c = buffer[bufferindex++];
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+
+#define READ_COPY_BUFFER(dst, len) \
+ for(l = len, p = (unsigned char *)dst; l > 0; ) { \
+ unsigned int lcopy; \
+ if((int)bufferindex >= n) { \
+ n = read(s, buffer, sizeof(buffer)); \
+ if(n<=0) break; \
+ bufferindex = 0; \
+ } \
+ lcopy = MIN(l, (n - bufferindex)); \
+ memcpy(p, buffer + bufferindex, lcopy); \
+ l -= lcopy; \
+ p += lcopy; \
+ bufferindex += lcopy; \
+ }
+
+#define READ_DISCARD_BUFFER(len) \
+ for(l = len; l > 0; ) { \
+ unsigned int lcopy; \
+ if(bufferindex >= n) { \
+ n = read(s, buffer, sizeof(buffer)); \
+ if(n<=0) break; \
+ bufferindex = 0; \
+ } \
+ lcopy = MIN(l, (n - bufferindex)); \
+ l -= lcopy; \
+ bufferindex += lcopy; \
+ }
+
+int
+connectToMiniSSDPD(const char * socketpath)
+{
+ int s;
+ struct sockaddr_un addr;
+#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
+ struct timeval timeout;
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(s < 0)
+ {
+ /*syslog(LOG_ERR, "socket(unix): %m");*/
+ perror("socket(unix)");
+ return MINISSDPC_SOCKET_ERROR;
+ }
+#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
+ /* setting a 3 seconds timeout */
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+ if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
+ {
+ perror("setsockopt");
+ }
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+ if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
+ {
+ perror("setsockopt");
+ }
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
+ if(!socketpath)
+ socketpath = "/var/run/minissdpd.sock";
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
+ /* TODO : check if we need to handle the EINTR */
+ if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
+ {
+ /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
+ close(s);
+ return MINISSDPC_SOCKET_ERROR;
+ }
+ return s;
+}
+
+int
+disconnectFromMiniSSDPD(int s)
+{
+ if (close(s) < 0)
+ return MINISSDPC_SOCKET_ERROR;
+ return MINISSDPC_SUCCESS;
+}
+
+int
+requestDevicesFromMiniSSDPD(int s, const char * devtype)
+{
+ unsigned char buffer[256];
+ unsigned char * p;
+ unsigned int stsize, l;
+
+ stsize = strlen(devtype);
+ if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
+ {
+ buffer[0] = 3; /* request type 3 : everything */
+ }
+ else
+ {
+ buffer[0] = 1; /* request type 1 : request devices/services by type */
+ }
+ p = buffer + 1;
+ l = stsize; CODELENGTH(l, p);
+ if(p + stsize > buffer + sizeof(buffer))
+ {
+ /* devtype is too long ! */
+#ifdef DEBUG
+ fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
+ stsize, (unsigned)sizeof(buffer));
+#endif /* DEBUG */
+ return MINISSDPC_INVALID_INPUT;
+ }
+ memcpy(p, devtype, stsize);
+ p += stsize;
+ if(write(s, buffer, p - buffer) < 0)
+ {
+ /*syslog(LOG_ERR, "write(): %m");*/
+ perror("minissdpc.c: write()");
+ return MINISSDPC_SOCKET_ERROR;
+ }
+ return MINISSDPC_SUCCESS;
+}
+
+struct UPNPDev *
+receiveDevicesFromMiniSSDPD(int s, int * error)
+{
+ struct UPNPDev * tmp;
+ struct UPNPDev * devlist = NULL;
+ unsigned char buffer[256];
+ ssize_t n;
+ unsigned char * p;
+ unsigned char * url;
+ unsigned char * st;
+ unsigned int bufferindex;
+ unsigned int i, ndev;
+ unsigned int urlsize, stsize, usnsize, l;
+
+ n = read(s, buffer, sizeof(buffer));
+ if(n<=0)
+ {
+ perror("minissdpc.c: read()");
+ if (error)
+ *error = MINISSDPC_SOCKET_ERROR;
+ return NULL;
+ }
+ ndev = buffer[0];
+ bufferindex = 1;
+ for(i = 0; i < ndev; i++)
+ {
+ DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
+ if(n<=0) {
+ if (error)
+ *error = MINISSDPC_INVALID_SERVER_REPLY;
+ return devlist;
+ }
+#ifdef DEBUG
+ printf(" urlsize=%u", urlsize);
+#endif /* DEBUG */
+ url = malloc(urlsize);
+ if(url == NULL) {
+ if (error)
+ *error = MINISSDPC_MEMORY_ERROR;
+ return devlist;
+ }
+ READ_COPY_BUFFER(url, urlsize);
+ if(n<=0) {
+ if (error)
+ *error = MINISSDPC_INVALID_SERVER_REPLY;
+ goto free_url_and_return;
+ }
+ DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
+ if(n<=0) {
+ if (error)
+ *error = MINISSDPC_INVALID_SERVER_REPLY;
+ goto free_url_and_return;
+ }
+#ifdef DEBUG
+ printf(" stsize=%u", stsize);
+#endif /* DEBUG */
+ st = malloc(stsize);
+ if (st == NULL) {
+ if (error)
+ *error = MINISSDPC_MEMORY_ERROR;
+ goto free_url_and_return;
+ }
+ READ_COPY_BUFFER(st, stsize);
+ if(n<=0) {
+ if (error)
+ *error = MINISSDPC_INVALID_SERVER_REPLY;
+ goto free_url_and_st_and_return;
+ }
+ DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
+ if(n<=0) {
+ if (error)
+ *error = MINISSDPC_INVALID_SERVER_REPLY;
+ goto free_url_and_st_and_return;
+ }
+#ifdef DEBUG
+ printf(" usnsize=%u\n", usnsize);
+#endif /* DEBUG */
+ tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
+ if(tmp == NULL) {
+ if (error)
+ *error = MINISSDPC_MEMORY_ERROR;
+ goto free_url_and_st_and_return;
+ }
+ tmp->pNext = devlist;
+ tmp->descURL = tmp->buffer;
+ tmp->st = tmp->buffer + 1 + urlsize;
+ memcpy(tmp->buffer, url, urlsize);
+ tmp->buffer[urlsize] = '\0';
+ memcpy(tmp->st, st, stsize);
+ tmp->buffer[urlsize+1+stsize] = '\0';
+ free(url);
+ free(st);
+ url = NULL;
+ st = NULL;
+ tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
+ READ_COPY_BUFFER(tmp->usn, usnsize);
+ if(n<=0) {
+ if (error)
+ *error = MINISSDPC_INVALID_SERVER_REPLY;
+ goto free_tmp_and_return;
+ }
+ tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
+ tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
+ devlist = tmp;
+ }
+ if (error)
+ *error = MINISSDPC_SUCCESS;
+ return devlist;
+
+free_url_and_st_and_return:
+ free(st);
+free_url_and_return:
+ free(url);
+ return devlist;
+
+free_tmp_and_return:
+ free(tmp);
+ return devlist;
+}
+
+#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
+
+/* parseMSEARCHReply()
+ * the last 4 arguments are filled during the parsing :
+ * - location/locationsize : "location:" field of the SSDP reply packet
+ * - st/stsize : "st:" field of the SSDP reply packet.
+ * The strings are NOT null terminated */
+static void
+parseMSEARCHReply(const char * reply, int size,
+ const char * * location, int * locationsize,
+ const char * * st, int * stsize,
+ const char * * usn, int * usnsize)
+{
+ int a, b, i;
+ i = 0;
+ a = i; /* start of the line */
+ b = 0; /* end of the "header" (position of the colon) */
+ while(i<size)
+ {
+ switch(reply[i])
+ {
+ case ':':
+ if(b==0)
+ {
+ b = i; /* end of the "header" */
+ /*for(j=a; j<b; j++)
+ {
+ putchar(reply[j]);
+ }
+ */
+ }
+ break;
+ case '\x0a':
+ case '\x0d':
+ if(b!=0)
+ {
+ /*for(j=b+1; j<i; j++)
+ {
+ putchar(reply[j]);
+ }
+ putchar('\n');*/
+ /* skip the colon and white spaces */
+ do { b++; } while(reply[b]==' ');
+ if(0==strncasecmp(reply+a, "location", 8))
+ {
+ *location = reply+b;
+ *locationsize = i-b;
+ }
+ else if(0==strncasecmp(reply+a, "st", 2))
+ {
+ *st = reply+b;
+ *stsize = i-b;
+ }
+ else if(0==strncasecmp(reply+a, "usn", 3))
+ {
+ *usn = reply+b;
+ *usnsize = i-b;
+ }
+ b = 0;
+ }
+ a = i+1;
+ break;
+ default:
+ break;
+ }
+ i++;
+ }
+}
+
+/* port upnp discover : SSDP protocol */
+#define SSDP_PORT 1900
+#define XSTR(s) STR(s)
+#define STR(s) #s
+#define UPNP_MCAST_ADDR "239.255.255.250"
+/* for IPv6 */
+#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
+#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
+
+/* direct discovery if minissdpd responses are not sufficient */
+/* ssdpDiscoverDevices() :
+ * return a chained list of all devices found or NULL if
+ * no devices was found.
+ * It is up to the caller to free the chained list
+ * delay is in millisecond (poll).
+ * UDA v1.1 says :
+ * The TTL for the IP packet SHOULD default to 2 and
+ * SHOULD be configurable. */
+struct UPNPDev *
+ssdpDiscoverDevices(const char * const deviceTypes[],
+ int delay, const char * multicastif,
+ int localport,
+ int ipv6, unsigned char ttl,
+ int * error,
+ int searchalltypes)
+{
+ struct UPNPDev * tmp;
+ struct UPNPDev * devlist = 0;
+ unsigned int scope_id = 0;
+ int opt = 1;
+ static const char MSearchMsgFmt[] =
+ "M-SEARCH * HTTP/1.1\r\n"
+ "HOST: %s:" XSTR(SSDP_PORT) "\r\n"
+ "ST: %s\r\n"
+ "MAN: \"ssdp:discover\"\r\n"
+ "MX: %u\r\n"
+ "\r\n";
+ int deviceIndex;
+ char bufr[1536]; /* reception and emission buffer */
+ int sudp;
+ int n;
+ struct sockaddr_storage sockudp_r;
+ unsigned int mx;
+#ifdef NO_GETADDRINFO
+ struct sockaddr_storage sockudp_w;
+#else
+ int rv;
+ struct addrinfo hints, *servinfo, *p;
+#endif
+#ifdef _WIN32
+ MIB_IPFORWARDROW ip_forward;
+ unsigned long _ttl = (unsigned long)ttl;
+#endif
+ int linklocal = 1;
+
+ if(error)
+ *error = MINISSDPC_UNKNOWN_ERROR;
+
+ if(localport==UPNP_LOCAL_PORT_SAME)
+ localport = SSDP_PORT;
+
+#ifdef _WIN32
+ sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#else
+ sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
+#endif
+ if(sudp < 0)
+ {
+ if(error)
+ *error = MINISSDPC_SOCKET_ERROR;
+ PRINT_SOCKET_ERROR("socket");
+ return NULL;
+ }
+ /* reception */
+ memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
+ if(ipv6) {
+ struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
+ p->sin6_family = AF_INET6;
+ if(localport > 0 && localport < 65536)
+ p->sin6_port = htons((unsigned short)localport);
+ p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
+ } else {
+ struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
+ p->sin_family = AF_INET;
+ if(localport > 0 && localport < 65536)
+ p->sin_port = htons((unsigned short)localport);
+ p->sin_addr.s_addr = INADDR_ANY;
+ }
+#ifdef _WIN32
+/* This code could help us to use the right Network interface for
+ * SSDP multicast traffic */
+/* Get IP associated with the index given in the ip_forward struct
+ * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
+ if(!ipv6
+ && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
+ DWORD dwRetVal = 0;
+ PMIB_IPADDRTABLE pIPAddrTable;
+ DWORD dwSize = 0;
+#ifdef DEBUG
+ IN_ADDR IPAddr;
+#endif
+ int i;
+#ifdef DEBUG
+ printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
+#endif
+ pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
+ if(pIPAddrTable) {
+ if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
+ free(pIPAddrTable);
+ pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
+ }
+ }
+ if(pIPAddrTable) {
+ dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
+ if (dwRetVal == NO_ERROR) {
+#ifdef DEBUG
+ printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
+#endif
+ for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
+#ifdef DEBUG
+ printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
+ IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
+ printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
+ IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
+ printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
+ IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
+ printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
+ printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
+ printf("\tType and State[%d]:", i);
+ printf("\n");
+#endif
+ if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
+ /* Set the address of this interface to be used */
+ struct in_addr mc_if;
+ memset(&mc_if, 0, sizeof(mc_if));
+ mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
+ PRINT_SOCKET_ERROR("setsockopt");
+ }
+ ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
+#ifndef DEBUG
+ break;
+#endif
+ }
+ }
+ }
+ free(pIPAddrTable);
+ pIPAddrTable = NULL;
+ }
+ }
+#endif /* _WIN32 */
+
+#ifdef _WIN32
+ if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
+#else
+ if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
+#endif
+ {
+ if(error)
+ *error = MINISSDPC_SOCKET_ERROR;
+ PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
+ return NULL;
+ }
+
+#ifdef _WIN32
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
+#else /* _WIN32 */
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
+#endif /* _WIN32 */
+ {
+ /* not a fatal error */
+ PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
+ }
+
+ if(multicastif)
+ {
+ if(ipv6) {
+#if !defined(_WIN32)
+ /* according to MSDN, if_nametoindex() is supported since
+ * MS Windows Vista and MS Windows Server 2008.
+ * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
+ unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
+ if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt");
+ }
+#else
+#ifdef DEBUG
+ printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
+#endif
+#endif
+ } else {
+ struct in_addr mc_if;
+ mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
+ if(mc_if.s_addr != INADDR_NONE)
+ {
+ ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt");
+ }
+ } else {
+#ifdef HAS_IP_MREQN
+ /* was not an ip address, try with an interface name */
+ struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
+ memset(&reqn, 0, sizeof(struct ip_mreqn));
+ reqn.imr_ifindex = if_nametoindex(multicastif);
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt");
+ }
+#else
+#ifdef DEBUG
+ printf("Setting of multicast interface not supported with interface name.\n");
+#endif
+#endif
+ }
+ }
+ }
+
+ /* Before sending the packed, we first "bind" in order to be able
+ * to receive the response */
+ if (bind(sudp, (const struct sockaddr *)&sockudp_r,
+ ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
+ {
+ if(error)
+ *error = MINISSDPC_SOCKET_ERROR;
+ PRINT_SOCKET_ERROR("bind");
+ closesocket(sudp);
+ return NULL;
+ }
+
+ if(error)
+ *error = MINISSDPC_SUCCESS;
+ /* Calculating maximum response time in seconds */
+ mx = ((unsigned int)delay) / 1000u;
+ if(mx == 0) {
+ mx = 1;
+ delay = 1000;
+ }
+ /* receiving SSDP response packet */
+ for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
+ /* sending the SSDP M-SEARCH packet */
+ n = snprintf(bufr, sizeof(bufr),
+ MSearchMsgFmt,
+ ipv6 ?
+ (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
+ : UPNP_MCAST_ADDR,
+ deviceTypes[deviceIndex], mx);
+ if ((unsigned int)n >= sizeof(bufr)) {
+ if(error)
+ *error = MINISSDPC_MEMORY_ERROR;
+ goto error;
+ }
+#ifdef DEBUG
+ /*printf("Sending %s", bufr);*/
+ printf("Sending M-SEARCH request to %s with ST: %s\n",
+ ipv6 ?
+ (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
+ : UPNP_MCAST_ADDR,
+ deviceTypes[deviceIndex]);
+#endif
+#ifdef NO_GETADDRINFO
+ /* the following code is not using getaddrinfo */
+ /* emission */
+ memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
+ if(ipv6) {
+ struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
+ p->sin6_family = AF_INET6;
+ p->sin6_port = htons(SSDP_PORT);
+ inet_pton(AF_INET6,
+ linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
+ &(p->sin6_addr));
+ } else {
+ struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
+ p->sin_family = AF_INET;
+ p->sin_port = htons(SSDP_PORT);
+ p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
+ }
+ n = sendto(sudp, bufr, n, 0, &sockudp_w,
+ ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
+ if (n < 0) {
+ if(error)
+ *error = MINISSDPC_SOCKET_ERROR;
+ PRINT_SOCKET_ERROR("sendto");
+ break;
+ }
+#else /* #ifdef NO_GETADDRINFO */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
+ hints.ai_socktype = SOCK_DGRAM;
+ /*hints.ai_flags = */
+ if ((rv = getaddrinfo(ipv6
+ ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
+ : UPNP_MCAST_ADDR,
+ XSTR(SSDP_PORT), &hints, &servinfo)) != 0) {
+ if(error)
+ *error = MINISSDPC_SOCKET_ERROR;
+#ifdef _WIN32
+ fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
+#else
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
+#endif
+ break;
+ }
+ for(p = servinfo; p; p = p->ai_next) {
+ n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
+ if (n < 0) {
+#ifdef DEBUG
+ char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+ if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
+ sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
+ fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
+ }
+#endif
+ PRINT_SOCKET_ERROR("sendto");
+ continue;
+ }
+ }
+ freeaddrinfo(servinfo);
+ if(n < 0) {
+ if(error)
+ *error = MINISSDPC_SOCKET_ERROR;
+ break;
+ }
+#endif /* #ifdef NO_GETADDRINFO */
+ /* Waiting for SSDP REPLY packet to M-SEARCH
+ * if searchalltypes is set, enter the loop only
+ * when the last deviceType is reached */
+ if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do {
+ n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
+ if (n < 0) {
+ /* error */
+ if(error)
+ *error = MINISSDPC_SOCKET_ERROR;
+ goto error;
+ } else if (n == 0) {
+ /* no data or Time Out */
+#ifdef DEBUG
+ printf("NODATA or TIMEOUT\n");
+#endif /* DEBUG */
+ if (devlist && !searchalltypes) {
+ /* found some devices, stop now*/
+ if(error)
+ *error = MINISSDPC_SUCCESS;
+ goto error;
+ }
+ } else {
+ const char * descURL=NULL;
+ int urlsize=0;
+ const char * st=NULL;
+ int stsize=0;
+ const char * usn=NULL;
+ int usnsize=0;
+ parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
+ if(st&&descURL) {
+#ifdef DEBUG
+ printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
+ stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
+#endif /* DEBUG */
+ for(tmp=devlist; tmp; tmp = tmp->pNext) {
+ if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
+ tmp->descURL[urlsize] == '\0' &&
+ memcmp(tmp->st, st, stsize) == 0 &&
+ tmp->st[stsize] == '\0' &&
+ (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) &&
+ tmp->usn[usnsize] == '\0')
+ break;
+ }
+ /* at the exit of the loop above, tmp is null if
+ * no duplicate device was found */
+ if(tmp)
+ continue;
+ tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
+ if(!tmp) {
+ /* memory allocation error */
+ if(error)
+ *error = MINISSDPC_MEMORY_ERROR;
+ goto error;
+ }
+ tmp->pNext = devlist;
+ tmp->descURL = tmp->buffer;
+ tmp->st = tmp->buffer + 1 + urlsize;
+ tmp->usn = tmp->st + 1 + stsize;
+ memcpy(tmp->buffer, descURL, urlsize);
+ tmp->buffer[urlsize] = '\0';
+ memcpy(tmp->st, st, stsize);
+ tmp->buffer[urlsize+1+stsize] = '\0';
+ if(usn != NULL)
+ memcpy(tmp->usn, usn, usnsize);
+ tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
+ tmp->scope_id = scope_id;
+ devlist = tmp;
+ }
+ }
+ } while(n > 0);
+ if(ipv6) {
+ /* switch linklocal flag */
+ if(linklocal) {
+ linklocal = 0;
+ --deviceIndex;
+ } else {
+ linklocal = 1;
+ }
+ }
+ }
+error:
+ closesocket(sudp);
+ return devlist;
+}
+
diff --git a/ext/miniupnpc/minissdpc.h b/ext/miniupnpc/minissdpc.h
new file mode 100644
index 00000000..a5c622b2
--- /dev/null
+++ b/ext/miniupnpc/minissdpc.h
@@ -0,0 +1,58 @@
+/* $Id: minissdpc.h,v 1.7 2015/10/08 16:15:47 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef MINISSDPC_H_INCLUDED
+#define MINISSDPC_H_INCLUDED
+
+#include "miniupnpc_declspec.h"
+#include "upnpdev.h"
+
+/* error codes : */
+#define MINISSDPC_SUCCESS (0)
+#define MINISSDPC_UNKNOWN_ERROR (-1)
+#define MINISSDPC_SOCKET_ERROR (-101)
+#define MINISSDPC_MEMORY_ERROR (-102)
+#define MINISSDPC_INVALID_INPUT (-103)
+#define MINISSDPC_INVALID_SERVER_REPLY (-104)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
+
+MINIUPNP_LIBSPEC int
+connectToMiniSSDPD(const char * socketpath);
+
+MINIUPNP_LIBSPEC int
+disconnectFromMiniSSDPD(int fd);
+
+MINIUPNP_LIBSPEC int
+requestDevicesFromMiniSSDPD(int fd, const char * devtype);
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+receiveDevicesFromMiniSSDPD(int fd, int * error);
+
+#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+ssdpDiscoverDevices(const char * const deviceTypes[],
+ int delay, const char * multicastif,
+ int localport,
+ int ipv6, unsigned char ttl,
+ int * error,
+ int searchalltypes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/ext/miniupnpc/miniupnpc.c b/ext/miniupnpc/miniupnpc.c
new file mode 100644
index 00000000..56638881
--- /dev/null
+++ b/ext/miniupnpc/miniupnpc.c
@@ -0,0 +1,685 @@
+#define _CRT_SECURE_NO_WARNINGS
+/* $Id: miniupnpc.c,v 1.141 2015/10/26 17:05:07 nanard Exp $ */
+/* vim: tabstop=4 shiftwidth=4 noexpandtab */
+/* Project : miniupnp
+ * Web : http://miniupnp.free.fr/
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENSE file. */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef _WIN32
+/* Win32 Specific includes and defines */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#include <iphlpapi.h>
+#define snprintf _snprintf
+#define strdup _strdup
+#ifndef strncasecmp
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define strncasecmp _memicmp
+#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
+#define strncasecmp memicmp
+#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
+#endif /* #ifndef strncasecmp */
+#define MAXHOSTNAMELEN 64
+#else /* #ifdef _WIN32 */
+/* Standard POSIX includes */
+#include <unistd.h>
+#if defined(__amigaos__) && !defined(__amigaos4__)
+/* Amiga OS 3 specific stuff */
+#define socklen_t int
+#else
+#include <sys/select.h>
+#endif
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#if !defined(__amigaos__) && !defined(__amigaos4__)
+#include <poll.h>
+#endif
+#include <strings.h>
+#include <errno.h>
+#define closesocket close
+#endif /* #else _WIN32 */
+#ifdef __GNU__
+#define MAXHOSTNAMELEN 64
+#endif
+
+
+#include "miniupnpc.h"
+#include "minissdpc.h"
+#include "miniwget.h"
+#include "minisoap.h"
+#include "minixml.h"
+#include "upnpcommands.h"
+#include "connecthostport.h"
+
+/* compare the begining of a string with a constant string */
+#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define SOAPPREFIX "s"
+#define SERVICEPREFIX "u"
+#define SERVICEPREFIX2 'u'
+
+/* root description parsing */
+MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
+{
+ struct xmlparser parser;
+ /* xmlparser object */
+ parser.xmlstart = buffer;
+ parser.xmlsize = bufsize;
+ parser.data = data;
+ parser.starteltfunc = IGDstartelt;
+ parser.endeltfunc = IGDendelt;
+ parser.datafunc = IGDdata;
+ parser.attfunc = 0;
+ parsexml(&parser);
+#ifdef DEBUG
+ printIGD(data);
+#endif
+}
+
+/* simpleUPnPcommand2 :
+ * not so simple !
+ * return values :
+ * pointer - OK
+ * NULL - error */
+char * simpleUPnPcommand2(int s, const char * url, const char * service,
+ const char * action, struct UPNParg * args,
+ int * bufsize, const char * httpversion)
+{
+ char hostname[MAXHOSTNAMELEN+1];
+ unsigned short port = 0;
+ char * path;
+ char soapact[128];
+ char soapbody[2048];
+ int soapbodylen;
+ char * buf;
+ int n;
+
+ *bufsize = 0;
+ snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
+ if(args==NULL)
+ {
+ soapbodylen = snprintf(soapbody, sizeof(soapbody),
+ "<?xml version=\"1.0\"?>\r\n"
+ "<" SOAPPREFIX ":Envelope "
+ "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+ SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ "<" SOAPPREFIX ":Body>"
+ "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
+ "</" SERVICEPREFIX ":%s>"
+ "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
+ "\r\n", action, service, action);
+ if ((unsigned int)soapbodylen >= sizeof(soapbody))
+ return NULL;
+ }
+ else
+ {
+ char * p;
+ const char * pe, * pv;
+ const char * const pend = soapbody + sizeof(soapbody);
+ soapbodylen = snprintf(soapbody, sizeof(soapbody),
+ "<?xml version=\"1.0\"?>\r\n"
+ "<" SOAPPREFIX ":Envelope "
+ "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+ SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ "<" SOAPPREFIX ":Body>"
+ "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
+ action, service);
+ if ((unsigned int)soapbodylen >= sizeof(soapbody))
+ return NULL;
+ p = soapbody + soapbodylen;
+ while(args->elt)
+ {
+ if(p >= pend) /* check for space to write next byte */
+ return NULL;
+ *(p++) = '<';
+
+ pe = args->elt;
+ while(p < pend && *pe)
+ *(p++) = *(pe++);
+
+ if(p >= pend) /* check for space to write next byte */
+ return NULL;
+ *(p++) = '>';
+
+ if((pv = args->val))
+ {
+ while(p < pend && *pv)
+ *(p++) = *(pv++);
+ }
+
+ if((p+2) > pend) /* check for space to write next 2 bytes */
+ return NULL;
+ *(p++) = '<';
+ *(p++) = '/';
+
+ pe = args->elt;
+ while(p < pend && *pe)
+ *(p++) = *(pe++);
+
+ if(p >= pend) /* check for space to write next byte */
+ return NULL;
+ *(p++) = '>';
+
+ args++;
+ }
+ if((p+4) > pend) /* check for space to write next 4 bytes */
+ return NULL;
+ *(p++) = '<';
+ *(p++) = '/';
+ *(p++) = SERVICEPREFIX2;
+ *(p++) = ':';
+
+ pe = action;
+ while(p < pend && *pe)
+ *(p++) = *(pe++);
+
+ strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
+ pend - p);
+ if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
+ return NULL;
+ }
+ if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
+ if(s < 0) {
+ s = connecthostport(hostname, port, 0);
+ if(s < 0) {
+ /* failed to connect */
+ return NULL;
+ }
+ }
+
+ n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion);
+ if(n<=0) {
+#ifdef DEBUG
+ printf("Error sending SOAP request\n");
+#endif
+ closesocket(s);
+ return NULL;
+ }
+
+ buf = getHTTPResponse(s, bufsize);
+#ifdef DEBUG
+ if(*bufsize > 0 && buf)
+ {
+ printf("SOAP Response :\n%.*s\n", *bufsize, buf);
+ }
+#endif
+ closesocket(s);
+ return buf;
+}
+
+/* simpleUPnPcommand :
+ * not so simple !
+ * return values :
+ * pointer - OK
+ * NULL - error */
+char * simpleUPnPcommand(int s, const char * url, const char * service,
+ const char * action, struct UPNParg * args,
+ int * bufsize)
+{
+ char * buf;
+
+#if 1
+ buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
+#else
+ buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0");
+ if (!buf || *bufsize == 0)
+ {
+#if DEBUG
+ printf("Error or no result from SOAP request; retrying with HTTP/1.1\n");
+#endif
+ buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1");
+ }
+#endif
+ return buf;
+}
+
+/* upnpDiscoverDevices() :
+ * return a chained list of all devices found or NULL if
+ * no devices was found.
+ * It is up to the caller to free the chained list
+ * delay is in millisecond (poll).
+ * UDA v1.1 says :
+ * The TTL for the IP packet SHOULD default to 2 and
+ * SHOULD be configurable. */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverDevices(const char * const deviceTypes[],
+ int delay, const char * multicastif,
+ const char * minissdpdsock, int localport,
+ int ipv6, unsigned char ttl,
+ int * error,
+ int searchalltypes)
+{
+ struct UPNPDev * tmp;
+ struct UPNPDev * devlist = 0;
+#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
+ int deviceIndex;
+#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
+
+ if(error)
+ *error = UPNPDISCOVER_UNKNOWN_ERROR;
+#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
+ /* first try to get infos from minissdpd ! */
+ if(!minissdpdsock)
+ minissdpdsock = "/var/run/minissdpd.sock";
+ for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
+ struct UPNPDev * minissdpd_devlist;
+ int only_rootdevice = 1;
+ minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
+ minissdpdsock, 0);
+ if(minissdpd_devlist) {
+#ifdef DEBUG
+ printf("returned by MiniSSDPD: %s\t%s\n",
+ minissdpd_devlist->st, minissdpd_devlist->descURL);
+#endif /* DEBUG */
+ if(!strstr(minissdpd_devlist->st, "rootdevice"))
+ only_rootdevice = 0;
+ for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
+#ifdef DEBUG
+ printf("returned by MiniSSDPD: %s\t%s\n",
+ tmp->pNext->st, tmp->pNext->descURL);
+#endif /* DEBUG */
+ if(!strstr(tmp->st, "rootdevice"))
+ only_rootdevice = 0;
+ }
+ tmp->pNext = devlist;
+ devlist = minissdpd_devlist;
+ if(!searchalltypes && !only_rootdevice)
+ break;
+ }
+ }
+ for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
+ /* We return what we have found if it was not only a rootdevice */
+ if(!strstr(tmp->st, "rootdevice")) {
+ if(error)
+ *error = UPNPDISCOVER_SUCCESS;
+ return devlist;
+ }
+ }
+#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
+
+ /* direct discovery if minissdpd responses are not sufficient */
+ {
+ struct UPNPDev * discovered_devlist;
+ discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
+ ipv6, ttl, error, searchalltypes);
+ if(devlist == NULL)
+ devlist = discovered_devlist;
+ else {
+ for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
+ tmp->pNext = discovered_devlist;
+ }
+ }
+ return devlist;
+}
+
+/* upnpDiscover() Discover IGD device */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscover(int delay, const char * multicastif,
+ const char * minissdpdsock, int localport,
+ int ipv6, unsigned char ttl,
+ int * error)
+{
+ static const char * const deviceList[] = {
+#if 0
+ "urn:schemas-upnp-org:device:InternetGatewayDevice:2",
+ "urn:schemas-upnp-org:service:WANIPConnection:2",
+#endif
+ "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
+ "urn:schemas-upnp-org:service:WANIPConnection:1",
+ "urn:schemas-upnp-org:service:WANPPPConnection:1",
+ "upnp:rootdevice",
+ /*"ssdp:all",*/
+ 0
+ };
+ return upnpDiscoverDevices(deviceList,
+ delay, multicastif, minissdpdsock, localport,
+ ipv6, ttl, error, 0);
+}
+
+/* upnpDiscoverAll() Discover all UPnP devices */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverAll(int delay, const char * multicastif,
+ const char * minissdpdsock, int localport,
+ int ipv6, unsigned char ttl,
+ int * error)
+{
+ static const char * const deviceList[] = {
+ /*"upnp:rootdevice",*/
+ "ssdp:all",
+ 0
+ };
+ return upnpDiscoverDevices(deviceList,
+ delay, multicastif, minissdpdsock, localport,
+ ipv6, ttl, error, 0);
+}
+
+/* upnpDiscoverDevice() Discover a specific device */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
+ const char * minissdpdsock, int localport,
+ int ipv6, unsigned char ttl,
+ int * error)
+{
+ const char * const deviceList[] = {
+ device,
+ 0
+ };
+ return upnpDiscoverDevices(deviceList,
+ delay, multicastif, minissdpdsock, localport,
+ ipv6, ttl, error, 0);
+}
+
+static char *
+build_absolute_url(const char * baseurl, const char * descURL,
+ const char * url, unsigned int scope_id)
+{
+ int l, n;
+ char * s;
+ const char * base;
+ char * p;
+#if defined(IF_NAMESIZE) && !defined(_WIN32)
+ char ifname[IF_NAMESIZE];
+#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
+ char scope_str[8];
+#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
+
+ if( (url[0] == 'h')
+ &&(url[1] == 't')
+ &&(url[2] == 't')
+ &&(url[3] == 'p')
+ &&(url[4] == ':')
+ &&(url[5] == '/')
+ &&(url[6] == '/'))
+ return strdup(url);
+ base = (baseurl[0] == '\0') ? descURL : baseurl;
+ n = strlen(base);
+ if(n > 7) {
+ p = strchr(base + 7, '/');
+ if(p)
+ n = p - base;
+ }
+ l = n + strlen(url) + 1;
+ if(url[0] != '/')
+ l++;
+ if(scope_id != 0) {
+#if defined(IF_NAMESIZE) && !defined(_WIN32)
+ if(if_indextoname(scope_id, ifname)) {
+ l += 3 + strlen(ifname); /* 3 == strlen(%25) */
+ }
+#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
+ /* under windows, scope is numerical */
+ l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
+#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
+ }
+ s = malloc(l);
+ if(s == NULL) return NULL;
+ memcpy(s, base, n);
+ if(scope_id != 0) {
+ s[n] = '\0';
+ if(0 == memcmp(s, "http://[fe80:", 13)) {
+ /* this is a linklocal IPv6 address */
+ p = strchr(s, ']');
+ if(p) {
+ /* insert %25<scope> into URL */
+#if defined(IF_NAMESIZE) && !defined(_WIN32)
+ memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
+ memcpy(p, "%25", 3);
+ memcpy(p + 3, ifname, strlen(ifname));
+ n += 3 + strlen(ifname);
+#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
+ memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
+ memcpy(p, "%25", 3);
+ memcpy(p + 3, scope_str, strlen(scope_str));
+ n += 3 + strlen(scope_str);
+#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
+ }
+ }
+ }
+ if(url[0] != '/')
+ s[n++] = '/';
+ memcpy(s + n, url, l - n);
+ return s;
+}
+
+/* Prepare the Urls for usage...
+ */
+MINIUPNP_LIBSPEC void
+GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
+ const char * descURL, unsigned int scope_id)
+{
+ /* strdup descURL */
+ urls->rootdescURL = strdup(descURL);
+
+ /* get description of WANIPConnection */
+ urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
+ data->first.scpdurl, scope_id);
+ urls->controlURL = build_absolute_url(data->urlbase, descURL,
+ data->first.controlurl, scope_id);
+ urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
+ data->CIF.controlurl, scope_id);
+ urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
+ data->IPv6FC.controlurl, scope_id);
+
+#ifdef DEBUG
+ printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
+ printf("urls->controlURL='%s'\n", urls->controlURL);
+ printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
+ printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
+#endif
+}
+
+MINIUPNP_LIBSPEC void
+FreeUPNPUrls(struct UPNPUrls * urls)
+{
+ if(!urls)
+ return;
+ free(urls->controlURL);
+ urls->controlURL = 0;
+ free(urls->ipcondescURL);
+ urls->ipcondescURL = 0;
+ free(urls->controlURL_CIF);
+ urls->controlURL_CIF = 0;
+ free(urls->controlURL_6FC);
+ urls->controlURL_6FC = 0;
+ free(urls->rootdescURL);
+ urls->rootdescURL = 0;
+}
+
+int
+UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
+{
+ char status[64];
+ unsigned int uptime;
+ status[0] = '\0';
+ UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
+ status, &uptime, NULL);
+ if(0 == strcmp("Connected", status))
+ return 1;
+ else if(0 == strcmp("Up", status)) /* Also accept "Up" */
+ return 1;
+ else
+ return 0;
+}
+
+
+/* UPNP_GetValidIGD() :
+ * return values :
+ * -1 = Internal error
+ * 0 = NO IGD found
+ * 1 = A valid connected IGD has been found
+ * 2 = A valid IGD has been found but it reported as
+ * not connected
+ * 3 = an UPnP device has been found but was not recognized as an IGD
+ *
+ * In any positive non zero return case, the urls and data structures
+ * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
+ * free allocated memory.
+ */
+MINIUPNP_LIBSPEC int
+UPNP_GetValidIGD(struct UPNPDev * devlist,
+ struct UPNPUrls * urls,
+ struct IGDdatas * data,
+ char * lanaddr, int lanaddrlen)
+{
+ struct xml_desc {
+ char * xml;
+ int size;
+ int is_igd;
+ } * desc = NULL;
+ struct UPNPDev * dev;
+ int ndev = 0;
+ int i;
+ int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
+ int n_igd = 0;
+ char extIpAddr[16];
+ if(!devlist)
+ {
+#ifdef DEBUG
+ printf("Empty devlist\n");
+#endif
+ return 0;
+ }
+ /* counting total number of devices in the list */
+ for(dev = devlist; dev; dev = dev->pNext)
+ ndev++;
+ if(ndev > 0)
+ {
+ desc = calloc(ndev, sizeof(struct xml_desc));
+ if(!desc)
+ return -1; /* memory allocation error */
+ }
+ /* Step 1 : downloading descriptions and testing type */
+ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
+ {
+ /* we should choose an internet gateway device.
+ * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
+ desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
+ lanaddr, lanaddrlen,
+ dev->scope_id);
+#ifdef DEBUG
+ if(!desc[i].xml)
+ {
+ printf("error getting XML description %s\n", dev->descURL);
+ }
+#endif
+ if(desc[i].xml)
+ {
+ memset(data, 0, sizeof(struct IGDdatas));
+ memset(urls, 0, sizeof(struct UPNPUrls));
+ parserootdesc(desc[i].xml, desc[i].size, data);
+ if(COMPARE(data->CIF.servicetype,
+ "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
+ {
+ desc[i].is_igd = 1;
+ n_igd++;
+ }
+ }
+ }
+ /* iterate the list to find a device depending on state */
+ for(state = 1; state <= 3; state++)
+ {
+ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
+ {
+ if(desc[i].xml)
+ {
+ memset(data, 0, sizeof(struct IGDdatas));
+ memset(urls, 0, sizeof(struct UPNPUrls));
+ parserootdesc(desc[i].xml, desc[i].size, data);
+ if(desc[i].is_igd || state >= 3 )
+ {
+ GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
+
+ /* in state 2 and 3 we dont test if device is connected ! */
+ if(state >= 2)
+ goto free_and_return;
+#ifdef DEBUG
+ printf("UPNPIGD_IsConnected(%s) = %d\n",
+ urls->controlURL,
+ UPNPIGD_IsConnected(urls, data));
+#endif
+ /* checks that status is connected AND there is a external IP address assigned */
+ if(UPNPIGD_IsConnected(urls, data)
+ && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0))
+ goto free_and_return;
+ FreeUPNPUrls(urls);
+ if(data->second.servicetype[0] != '\0') {
+#ifdef DEBUG
+ printf("We tried %s, now we try %s !\n",
+ data->first.servicetype, data->second.servicetype);
+#endif
+ /* swaping WANPPPConnection and WANIPConnection ! */
+ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service));
+ memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service));
+ memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service));
+ GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
+#ifdef DEBUG
+ printf("UPNPIGD_IsConnected(%s) = %d\n",
+ urls->controlURL,
+ UPNPIGD_IsConnected(urls, data));
+#endif
+ if(UPNPIGD_IsConnected(urls, data)
+ && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0))
+ goto free_and_return;
+ FreeUPNPUrls(urls);
+ }
+ }
+ memset(data, 0, sizeof(struct IGDdatas));
+ }
+ }
+ }
+ state = 0;
+free_and_return:
+ if(desc) {
+ for(i = 0; i < ndev; i++) {
+ if(desc[i].xml) {
+ free(desc[i].xml);
+ }
+ }
+ free(desc);
+ }
+ return state;
+}
+
+/* UPNP_GetIGDFromUrl()
+ * Used when skipping the discovery process.
+ * return value :
+ * 0 - Not ok
+ * 1 - OK */
+int
+UPNP_GetIGDFromUrl(const char * rootdescurl,
+ struct UPNPUrls * urls,
+ struct IGDdatas * data,
+ char * lanaddr, int lanaddrlen)
+{
+ char * descXML;
+ int descXMLsize = 0;
+ descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
+ lanaddr, lanaddrlen, 0);
+ if(descXML) {
+ memset(data, 0, sizeof(struct IGDdatas));
+ memset(urls, 0, sizeof(struct UPNPUrls));
+ parserootdesc(descXML, descXMLsize, data);
+ free(descXML);
+ descXML = NULL;
+ GetUPNPUrls(urls, data, rootdescurl, 0);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
diff --git a/ext/miniupnpc/miniupnpc.def b/ext/miniupnpc/miniupnpc.def
new file mode 100644
index 00000000..60e0bbe4
--- /dev/null
+++ b/ext/miniupnpc/miniupnpc.def
@@ -0,0 +1,45 @@
+LIBRARY
+; miniupnpc library
+ miniupnpc
+
+EXPORTS
+; miniupnpc
+ upnpDiscover
+ freeUPNPDevlist
+ parserootdesc
+ UPNP_GetValidIGD
+ UPNP_GetIGDFromUrl
+ GetUPNPUrls
+ FreeUPNPUrls
+; miniwget
+ miniwget
+ miniwget_getaddr
+; upnpcommands
+ UPNP_GetTotalBytesSent
+ UPNP_GetTotalBytesReceived
+ UPNP_GetTotalPacketsSent
+ UPNP_GetTotalPacketsReceived
+ UPNP_GetStatusInfo
+ UPNP_GetConnectionTypeInfo
+ UPNP_GetExternalIPAddress
+ UPNP_GetLinkLayerMaxBitRates
+ UPNP_AddPortMapping
+ UPNP_AddAnyPortMapping
+ UPNP_DeletePortMapping
+ UPNP_DeletePortMappingRange
+ UPNP_GetPortMappingNumberOfEntries
+ UPNP_GetSpecificPortMappingEntry
+ UPNP_GetGenericPortMappingEntry
+ UPNP_GetListOfPortMappings
+ UPNP_AddPinhole
+ UPNP_CheckPinholeWorking
+ UPNP_UpdatePinhole
+ UPNP_GetPinholePackets
+ UPNP_DeletePinhole
+ UPNP_GetFirewallStatus
+ UPNP_GetOutboundPinholeTimeout
+; upnperrors
+ strupnperror
+; portlistingparse
+ ParsePortListing
+ FreePortListing
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h b/ext/miniupnpc/miniupnpc.h
index 0eeabc23..dfbfa01f 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h
+++ b/ext/miniupnpc/miniupnpc.h
@@ -1,4 +1,4 @@
-/* $Id: miniupnpc.h,v 1.42 2015/07/21 13:16:55 nanard Exp $ */
+/* $Id: miniupnpc.h,v 1.48 2015/10/08 16:19:40 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard
@@ -10,6 +10,7 @@
#include "miniupnpc_declspec.h"
#include "igd_desc_parse.h"
+#include "upnpdev.h"
/* error codes : */
#define UPNPDISCOVER_SUCCESS (0)
@@ -18,8 +19,14 @@
#define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */
-#define MINIUPNPC_VERSION "1.9.20150721"
-#define MINIUPNPC_API_VERSION 13
+#define MINIUPNPC_VERSION "1.9.20151026"
+#define MINIUPNPC_API_VERSION 15
+
+/* Source port:
+ Using "1" as an alias for 1900 for backwards compatability
+ (presuming one would have used that for the "sameport" parameter) */
+#define UPNP_LOCAL_PORT_ANY 0
+#define UPNP_LOCAL_PORT_SAME 1
#ifdef __cplusplus
extern "C" {
@@ -33,14 +40,6 @@ simpleUPnPcommand(int, const char *, const char *,
const char *, struct UPNParg *,
int *);
-struct UPNPDev {
- struct UPNPDev * pNext;
- char * descURL;
- char * st;
- unsigned int scope_id;
- char buffer[2];
-};
-
/* upnpDiscover()
* discover UPnP devices on the network.
* The discovered devices are returned as a chained list.
@@ -52,40 +51,39 @@ struct UPNPDev {
* is NULL.
* If multicastif is not NULL, it will be used instead of the default
* multicast interface for sending SSDP discover packets.
- * If sameport is not null, SSDP packets will be sent from the source port
- * 1900 (same as destination port) otherwise system assign a source port.
+ * If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
+ * from the source port 1900 (same as destination port), if set to
+ * UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
+ * be attempted as the source port.
* "searchalltypes" parameter is useful when searching several types,
- * if 0, the discovery will stop with the first type returning results. */
+ * if 0, the discovery will stop with the first type returning results.
+ * TTL should default to 2. */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
- const char * minissdpdsock, int sameport,
- int ipv6,
+ const char * minissdpdsock, int localport,
+ int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverAll(int delay, const char * multicastif,
- const char * minissdpdsock, int sameport,
- int ipv6,
+ const char * minissdpdsock, int localport,
+ int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
- const char * minissdpdsock, int sameport,
- int ipv6,
+ const char * minissdpdsock, int localport,
+ int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
- const char * minissdpdsock, int sameport,
- int ipv6,
+ const char * minissdpdsock, int localport,
+ int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
-/* freeUPNPDevlist()
- * free list returned by upnpDiscover() */
-MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
-
/* parserootdesc() :
* parse root XML description of a UPnP device and fill the IGDdatas
* structure. */
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h b/ext/miniupnpc/miniupnpc_declspec.h
index 40adb922..40adb922 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
+++ b/ext/miniupnpc/miniupnpc_declspec.h
diff --git a/ext/miniupnpc/miniupnpcmodule.c b/ext/miniupnpc/miniupnpcmodule.c
new file mode 100644
index 00000000..a5bdce44
--- /dev/null
+++ b/ext/miniupnpc/miniupnpcmodule.c
@@ -0,0 +1,695 @@
+/* $Id: miniupnpcmodule.c,v 1.29 2015/10/26 17:01:30 nanard Exp $*/
+/* Project : miniupnp
+ * Author : Thomas BERNARD
+ * website : http://miniupnp.tuxfamily.org/
+ * copyright (c) 2007-2014 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENCE file. */
+#include <Python.h>
+#define MINIUPNP_STATICLIB
+#include "structmember.h"
+#include "miniupnpc.h"
+#include "upnpcommands.h"
+#include "upnperrors.h"
+
+/* for compatibility with Python < 2.4 */
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
+#endif
+
+#ifndef Py_RETURN_TRUE
+#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
+#endif
+
+#ifndef Py_RETURN_FALSE
+#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
+#endif
+
+/* for compatibility with Python < 3.0 */
+#ifndef PyVarObject_HEAD_INIT
+#define PyVarObject_HEAD_INIT(type, size) \
+ PyObject_HEAD_INIT(type) size,
+#endif
+
+#ifndef Py_TYPE
+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+
+typedef struct {
+ PyObject_HEAD
+ /* Type-specific fields go here. */
+ struct UPNPDev * devlist;
+ struct UPNPUrls urls;
+ struct IGDdatas data;
+ unsigned int discoverdelay; /* value passed to upnpDiscover() */
+ unsigned int localport; /* value passed to upnpDiscover() */
+ char lanaddr[40]; /* our ip address on the LAN */
+ char * multicastif;
+ char * minissdpdsocket;
+} UPnPObject;
+
+static PyMemberDef UPnP_members[] = {
+ {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
+ READONLY, "ip address on the LAN"
+ },
+ {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
+ 0/*READWRITE*/, "value in ms used to wait for SSDP responses"
+ },
+ {"localport", T_UINT, offsetof(UPnPObject, localport),
+ 0/*READWRITE*/,
+ "If localport is set to UPNP_LOCAL_PORT_SAME(1) "
+ "SSDP packets will be sent from the source port "
+ "1900 (same as destination port), if set to "
+ "UPNP_LOCAL_PORT_ANY(0) system assign a source "
+ "port, any other value will be attempted as the "
+ "source port"
+ },
+ /* T_STRING is allways readonly :( */
+ {"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
+ 0, "IP of the network interface to be used for multicast operations"
+ },
+ {"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),
+ 0, "path of the MiniSSDPd unix socket"
+ },
+ {NULL}
+};
+
+
+static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
+{
+ char* multicastif = NULL;
+ char* minissdpdsocket = NULL;
+ static char *kwlist[] = {
+ "multicastif", "minissdpdsocket", "discoverdelay",
+ "localport", NULL
+ };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,
+ &multicastif,
+ &minissdpdsocket,
+ &self->discoverdelay,
+ &self->localport))
+ return -1;
+
+ if(self->localport>1 &&
+ (self->localport>65534||self->localport<1024)) {
+ PyErr_SetString(PyExc_Exception, "Invalid localport value");
+ return -1;
+ }
+ if(multicastif)
+ self->multicastif = strdup(multicastif);
+ if(minissdpdsocket)
+ self->minissdpdsocket = strdup(minissdpdsocket);
+
+ return 0;
+}
+
+static void
+UPnPObject_dealloc(UPnPObject *self)
+{
+ freeUPNPDevlist(self->devlist);
+ FreeUPNPUrls(&self->urls);
+ free(self->multicastif);
+ free(self->minissdpdsocket);
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject *
+UPnP_discover(UPnPObject *self)
+{
+ struct UPNPDev * dev;
+ int i;
+ PyObject *res = NULL;
+ if(self->devlist)
+ {
+ freeUPNPDevlist(self->devlist);
+ self->devlist = 0;
+ }
+ Py_BEGIN_ALLOW_THREADS
+ self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
+ self->multicastif,
+ self->minissdpdsocket,
+ (int)self->localport,
+ 0/*ip v6*/,
+ 2/* TTL */,
+ 0/*error */);
+ Py_END_ALLOW_THREADS
+ /* Py_RETURN_NONE ??? */
+ for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
+ i++;
+ res = Py_BuildValue("i", i);
+ return res;
+}
+
+static PyObject *
+UPnP_selectigd(UPnPObject *self)
+{
+ int r;
+Py_BEGIN_ALLOW_THREADS
+ r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
+ self->lanaddr, sizeof(self->lanaddr));
+Py_END_ALLOW_THREADS
+ if(r)
+ {
+ return Py_BuildValue("s", self->urls.controlURL);
+ }
+ else
+ {
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
+ return NULL;
+ }
+}
+
+static PyObject *
+UPnP_totalbytesent(UPnPObject *self)
+{
+ UNSIGNED_INTEGER i;
+Py_BEGIN_ALLOW_THREADS
+ i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
+ self->data.CIF.servicetype);
+Py_END_ALLOW_THREADS
+#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
+ return Py_BuildValue("I", i);
+#else
+ return Py_BuildValue("i", (int)i);
+#endif
+}
+
+static PyObject *
+UPnP_totalbytereceived(UPnPObject *self)
+{
+ UNSIGNED_INTEGER i;
+Py_BEGIN_ALLOW_THREADS
+ i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
+ self->data.CIF.servicetype);
+Py_END_ALLOW_THREADS
+#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
+ return Py_BuildValue("I", i);
+#else
+ return Py_BuildValue("i", (int)i);
+#endif
+}
+
+static PyObject *
+UPnP_totalpacketsent(UPnPObject *self)
+{
+ UNSIGNED_INTEGER i;
+Py_BEGIN_ALLOW_THREADS
+ i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
+ self->data.CIF.servicetype);
+Py_END_ALLOW_THREADS
+#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
+ return Py_BuildValue("I", i);
+#else
+ return Py_BuildValue("i", (int)i);
+#endif
+}
+
+static PyObject *
+UPnP_totalpacketreceived(UPnPObject *self)
+{
+ UNSIGNED_INTEGER i;
+Py_BEGIN_ALLOW_THREADS
+ i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
+ self->data.CIF.servicetype);
+Py_END_ALLOW_THREADS
+#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
+ return Py_BuildValue("I", i);
+#else
+ return Py_BuildValue("i", (int)i);
+#endif
+}
+
+static PyObject *
+UPnP_statusinfo(UPnPObject *self)
+{
+ char status[64];
+ char lastconnerror[64];
+ unsigned int uptime = 0;
+ int r;
+ status[0] = '\0';
+ lastconnerror[0] = '\0';
+Py_BEGIN_ALLOW_THREADS
+ r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
+ status, &uptime, lastconnerror);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS) {
+#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
+ return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
+#else
+ return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror);
+#endif
+ } else {
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, strupnperror(r));
+ return NULL;
+ }
+}
+
+static PyObject *
+UPnP_connectiontype(UPnPObject *self)
+{
+ char connectionType[64];
+ int r;
+ connectionType[0] = '\0';
+Py_BEGIN_ALLOW_THREADS
+ r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
+ self->data.first.servicetype,
+ connectionType);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS) {
+ return Py_BuildValue("s", connectionType);
+ } else {
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, strupnperror(r));
+ return NULL;
+ }
+}
+
+static PyObject *
+UPnP_externalipaddress(UPnPObject *self)
+{
+ char externalIPAddress[40];
+ int r;
+ externalIPAddress[0] = '\0';
+Py_BEGIN_ALLOW_THREADS
+ r = UPNP_GetExternalIPAddress(self->urls.controlURL,
+ self->data.first.servicetype,
+ externalIPAddress);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS) {
+ return Py_BuildValue("s", externalIPAddress);
+ } else {
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, strupnperror(r));
+ return NULL;
+ }
+}
+
+/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
+ * remoteHost)
+ * protocol is 'UDP' or 'TCP' */
+static PyObject *
+UPnP_addportmapping(UPnPObject *self, PyObject *args)
+{
+ char extPort[6];
+ unsigned short ePort;
+ char inPort[6];
+ unsigned short iPort;
+ const char * proto;
+ const char * host;
+ const char * desc;
+ const char * remoteHost;
+ const char * leaseDuration = "0";
+ int r;
+ if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto,
+ &host, &iPort, &desc, &remoteHost))
+ return NULL;
+Py_BEGIN_ALLOW_THREADS
+ sprintf(extPort, "%hu", ePort);
+ sprintf(inPort, "%hu", iPort);
+ r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
+ extPort, inPort, host, desc, proto,
+ remoteHost, leaseDuration);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS)
+ {
+ Py_RETURN_TRUE;
+ }
+ else
+ {
+ // TODO: RAISE an Exception. See upnpcommands.h for errors codes.
+ // upnperrors.c
+ //Py_RETURN_FALSE;
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, strupnperror(r));
+ return NULL;
+ }
+}
+
+/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc,
+ * remoteHost)
+ * protocol is 'UDP' or 'TCP' */
+static PyObject *
+UPnP_addanyportmapping(UPnPObject *self, PyObject *args)
+{
+ char extPort[6];
+ unsigned short ePort;
+ char inPort[6];
+ unsigned short iPort;
+ char reservedPort[6];
+ const char * proto;
+ const char * host;
+ const char * desc;
+ const char * remoteHost;
+ const char * leaseDuration = "0";
+ int r;
+ if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, &host, &iPort, &desc, &remoteHost))
+ return NULL;
+Py_BEGIN_ALLOW_THREADS
+ sprintf(extPort, "%hu", ePort);
+ sprintf(inPort, "%hu", iPort);
+ r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype,
+ extPort, inPort, host, desc, proto,
+ remoteHost, leaseDuration, reservedPort);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS) {
+ return Py_BuildValue("i", atoi(reservedPort));
+ } else {
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, strupnperror(r));
+ return NULL;
+ }
+}
+
+
+/* DeletePortMapping(extPort, proto, removeHost='')
+ * proto = 'UDP', 'TCP' */
+static PyObject *
+UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
+{
+ char extPort[6];
+ unsigned short ePort;
+ const char * proto;
+ const char * remoteHost = "";
+ int r;
+ if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
+ return NULL;
+Py_BEGIN_ALLOW_THREADS
+ sprintf(extPort, "%hu", ePort);
+ r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
+ extPort, proto, remoteHost);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS) {
+ Py_RETURN_TRUE;
+ } else {
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, strupnperror(r));
+ return NULL;
+ }
+}
+
+/* DeletePortMappingRange(extPort, proto, removeHost='')
+ * proto = 'UDP', 'TCP' */
+static PyObject *
+UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args)
+{
+ char extPortStart[6];
+ unsigned short ePortStart;
+ char extPortEnd[6];
+ unsigned short ePortEnd;
+ const char * proto;
+ unsigned char manage;
+ char manageStr[1];
+ int r;
+ if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage))
+ return NULL;
+Py_BEGIN_ALLOW_THREADS
+ sprintf(extPortStart, "%hu", ePortStart);
+ sprintf(extPortEnd, "%hu", ePortEnd);
+ sprintf(manageStr, "%hhu", manage);
+ r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype,
+ extPortStart, extPortEnd, proto, manageStr);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS) {
+ Py_RETURN_TRUE;
+ } else {
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, strupnperror(r));
+ return NULL;
+ }
+}
+
+static PyObject *
+UPnP_getportmappingnumberofentries(UPnPObject *self)
+{
+ unsigned int n = 0;
+ int r;
+Py_BEGIN_ALLOW_THREADS
+ r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
+ self->data.first.servicetype,
+ &n);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS) {
+#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
+ return Py_BuildValue("I", n);
+#else
+ return Py_BuildValue("i", (int)n);
+#endif
+ } else {
+ /* TODO: have our own exception type ! */
+ PyErr_SetString(PyExc_Exception, strupnperror(r));
+ return NULL;
+ }
+}
+
+/* GetSpecificPortMapping(ePort, proto, remoteHost='')
+ * proto = 'UDP' or 'TCP' */
+static PyObject *
+UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
+{
+ char extPort[6];
+ unsigned short ePort;
+ const char * proto;
+ const char * remoteHost = "";
+ char intClient[40];
+ char intPort[6];
+ unsigned short iPort;
+ char desc[80];
+ char enabled[4];
+ char leaseDuration[16];
+ if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
+ return NULL;
+ extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
+ desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
+Py_BEGIN_ALLOW_THREADS
+ sprintf(extPort, "%hu", ePort);
+ UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
+ self->data.first.servicetype,
+ extPort, proto, remoteHost,
+ intClient, intPort,
+ desc, enabled, leaseDuration);
+Py_END_ALLOW_THREADS
+ if(intClient[0])
+ {
+ iPort = (unsigned short)atoi(intPort);
+ return Py_BuildValue("(s,H,s,O,i)",
+ intClient, iPort, desc,
+ PyBool_FromLong(atoi(enabled)),
+ atoi(leaseDuration));
+ }
+ else
+ {
+ Py_RETURN_NONE;
+ }
+}
+
+/* GetGenericPortMapping(index) */
+static PyObject *
+UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
+{
+ int i, r;
+ char index[8];
+ char intClient[40];
+ char intPort[6];
+ unsigned short iPort;
+ char extPort[6];
+ unsigned short ePort;
+ char protocol[4];
+ char desc[80];
+ char enabled[6];
+ char rHost[64];
+ char duration[16]; /* lease duration */
+ unsigned int dur;
+ if(!PyArg_ParseTuple(args, "i", &i))
+ return NULL;
+Py_BEGIN_ALLOW_THREADS
+ snprintf(index, sizeof(index), "%d", i);
+ rHost[0] = '\0'; enabled[0] = '\0';
+ duration[0] = '\0'; desc[0] = '\0';
+ extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
+ r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
+ self->data.first.servicetype,
+ index,
+ extPort, intClient, intPort,
+ protocol, desc, enabled, rHost,
+ duration);
+Py_END_ALLOW_THREADS
+ if(r==UPNPCOMMAND_SUCCESS)
+ {
+ ePort = (unsigned short)atoi(extPort);
+ iPort = (unsigned short)atoi(intPort);
+ dur = (unsigned int)strtoul(duration, 0, 0);
+#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
+ return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
+ ePort, protocol, intClient, iPort,
+ desc, enabled, rHost, dur);
+#else
+ return Py_BuildValue("(i,s,(s,i),s,s,s,i)",
+ (int)ePort, protocol, intClient, (int)iPort,
+ desc, enabled, rHost, (int)dur);
+#endif
+ }
+ else
+ {
+ Py_RETURN_NONE;
+ }
+}
+
+/* miniupnpc.UPnP object Method Table */
+static PyMethodDef UPnP_methods[] = {
+ {"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
+ "discover UPnP IGD devices on the network"
+ },
+ {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
+ "select a valid UPnP IGD among discovered devices"
+ },
+ {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
+ "return the total number of bytes sent by UPnP IGD"
+ },
+ {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
+ "return the total number of bytes received by UPnP IGD"
+ },
+ {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
+ "return the total number of packets sent by UPnP IGD"
+ },
+ {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
+ "return the total number of packets received by UPnP IGD"
+ },
+ {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
+ "return status and uptime"
+ },
+ {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
+ "return IGD WAN connection type"
+ },
+ {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
+ "return external IP address"
+ },
+ {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
+ "add a port mapping"
+ },
+ {"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS,
+ "add a port mapping, IGD to select alternative if necessary"
+ },
+ {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
+ "delete a port mapping"
+ },
+ {"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS,
+ "delete a range of port mappings"
+ },
+ {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
+ "-- non standard --"
+ },
+ {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
+ "get details about a specific port mapping entry"
+ },
+ {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
+ "get all details about the port mapping at index"
+ },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject UPnPType = {
+ PyVarObject_HEAD_INIT(NULL,
+ 0) /*ob_size*/
+ "miniupnpc.UPnP", /*tp_name*/
+ sizeof(UPnPObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)UPnPObject_dealloc,/*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "UPnP objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ UPnP_methods, /* tp_methods */
+ UPnP_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UPnP_init, /* tp_init */
+ 0, /* tp_alloc */
+#ifndef _WIN32
+ PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
+#else
+ 0,
+#endif
+};
+
+/* module methods */
+static PyMethodDef miniupnpc_methods[] = {
+ {NULL} /* Sentinel */
+};
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "miniupnpc", /* m_name */
+ "miniupnpc module.", /* m_doc */
+ -1, /* m_size */
+ miniupnpc_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+#endif
+
+#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+
+PyMODINIT_FUNC
+#if PY_MAJOR_VERSION >= 3
+PyInit_miniupnpc(void)
+#else
+initminiupnpc(void)
+#endif
+{
+ PyObject* m;
+
+#ifdef _WIN32
+ UPnPType.tp_new = PyType_GenericNew;
+#endif
+ if (PyType_Ready(&UPnPType) < 0)
+#if PY_MAJOR_VERSION >= 3
+ return 0;
+#else
+ return;
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&moduledef);
+#else
+ m = Py_InitModule3("miniupnpc", miniupnpc_methods,
+ "miniupnpc module.");
+#endif
+
+ Py_INCREF(&UPnPType);
+ PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
+
+#if PY_MAJOR_VERSION >= 3
+ return m;
+#endif
+}
+
diff --git a/ext/miniupnpc/miniupnpcstrings.h.cmake b/ext/miniupnpc/miniupnpcstrings.h.cmake
new file mode 100644
index 00000000..78c8fe9c
--- /dev/null
+++ b/ext/miniupnpc/miniupnpcstrings.h.cmake
@@ -0,0 +1,15 @@
+#ifndef MINIUPNPCSTRINGS_H_INCLUDED
+#define MINIUPNPCSTRINGS_H_INCLUDED
+
+#define OS_STRING "${CMAKE_SYSTEM_NAME}"
+#define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}"
+
+#if 0
+/* according to "UPnP Device Architecture 1.0" */
+#define UPNP_VERSION_STRING "UPnP/1.0"
+#else
+/* according to "UPnP Device Architecture 1.1" */
+#define UPNP_VERSION_STRING "UPnP/1.1"
+#endif
+
+#endif
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h b/ext/miniupnpc/miniupnpcstrings.h.in
index 80a1d757..68bf4293 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h
+++ b/ext/miniupnpc/miniupnpcstrings.h.in
@@ -8,8 +8,8 @@
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
#define MINIUPNPCSTRINGS_H_INCLUDED
-#define OS_STRING "Darwin/14.4.0"
-#define MINIUPNPC_VERSION_STRING "1.9"
+#define OS_STRING "OS/version"
+#define MINIUPNPC_VERSION_STRING "version"
#if 0
/* according to "UPnP Device Architecture 1.0" */
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h b/ext/miniupnpc/miniupnpctypes.h
index 591c32fb..591c32fb 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h
+++ b/ext/miniupnpc/miniupnpctypes.h
diff --git a/ext/miniupnpc/miniwget.c b/ext/miniupnpc/miniwget.c
new file mode 100644
index 00000000..d0dd721b
--- /dev/null
+++ b/ext/miniupnpc/miniwget.c
@@ -0,0 +1,633 @@
+#define _CRT_SECURE_NO_WARNINGS
+/* $Id: miniwget.c,v 1.72 2015/10/26 17:05:08 nanard Exp $ */
+/* Project : miniupnp
+ * Website : http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#define MAXHOSTNAMELEN 64
+#define snprintf _snprintf
+#define socklen_t int
+#ifndef strncasecmp
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define strncasecmp _memicmp
+#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
+#define strncasecmp memicmp
+#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
+#endif /* #ifndef strncasecmp */
+#else /* #ifdef _WIN32 */
+#include <unistd.h>
+#include <sys/param.h>
+#if defined(__amigaos__) && !defined(__amigaos4__)
+#define socklen_t int
+#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
+#include <sys/select.h>
+#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netdb.h>
+#define closesocket close
+#include <strings.h>
+#endif /* #else _WIN32 */
+#ifdef __GNU__
+#define MAXHOSTNAMELEN 64
+#endif /* __GNU__ */
+
+#ifndef MIN
+#define MIN(x,y) (((x)<(y))?(x):(y))
+#endif /* MIN */
+
+
+#ifdef _WIN32
+#define OS_STRING "Win32"
+#define MINIUPNPC_VERSION_STRING "1.9"
+#define UPNP_VERSION_STRING "UPnP/1.1"
+#else
+#include "miniupnpcstrings.h"
+#endif
+#include "miniwget.h"
+#include "connecthostport.h"
+#include "receivedata.h"
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+/*
+ * Read a HTTP response from a socket.
+ * Process Content-Length and Transfer-encoding headers.
+ * return a pointer to the content buffer, which length is saved
+ * to the length parameter.
+ */
+void *
+getHTTPResponse(int s, int * size)
+{
+ char buf[2048];
+ int n;
+ int endofheaders = 0;
+ int chunked = 0;
+ int content_length = -1;
+ unsigned int chunksize = 0;
+ unsigned int bytestocopy = 0;
+ /* buffers : */
+ char * header_buf;
+ unsigned int header_buf_len = 2048;
+ unsigned int header_buf_used = 0;
+ char * content_buf;
+ unsigned int content_buf_len = 2048;
+ unsigned int content_buf_used = 0;
+ char chunksize_buf[32];
+ unsigned int chunksize_buf_index;
+
+ header_buf = malloc(header_buf_len);
+ if(header_buf == NULL)
+ {
+#ifdef DEBUG
+ fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
+#endif /* DEBUG */
+ *size = -1;
+ return NULL;
+ }
+ content_buf = malloc(content_buf_len);
+ if(content_buf == NULL)
+ {
+ free(header_buf);
+#ifdef DEBUG
+ fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
+#endif /* DEBUG */
+ *size = -1;
+ return NULL;
+ }
+ chunksize_buf[0] = '\0';
+ chunksize_buf_index = 0;
+
+ while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0)
+ {
+ if(endofheaders == 0)
+ {
+ int i;
+ int linestart=0;
+ int colon=0;
+ int valuestart=0;
+ if(header_buf_used + n > header_buf_len) {
+ char * tmp = realloc(header_buf, header_buf_used + n);
+ if(tmp == NULL) {
+ /* memory allocation error */
+ free(header_buf);
+ free(content_buf);
+ *size = -1;
+ return NULL;
+ }
+ header_buf = tmp;
+ header_buf_len = header_buf_used + n;
+ }
+ memcpy(header_buf + header_buf_used, buf, n);
+ header_buf_used += n;
+ /* search for CR LF CR LF (end of headers)
+ * recognize also LF LF */
+ i = 0;
+ while(i < ((int)header_buf_used-1) && (endofheaders == 0)) {
+ if(header_buf[i] == '\r') {
+ i++;
+ if(header_buf[i] == '\n') {
+ i++;
+ if(i < (int)header_buf_used && header_buf[i] == '\r') {
+ i++;
+ if(i < (int)header_buf_used && header_buf[i] == '\n') {
+ endofheaders = i+1;
+ }
+ }
+ }
+ } else if(header_buf[i] == '\n') {
+ i++;
+ if(header_buf[i] == '\n') {
+ endofheaders = i+1;
+ }
+ }
+ i++;
+ }
+ if(endofheaders == 0)
+ continue;
+ /* parse header lines */
+ for(i = 0; i < endofheaders - 1; i++) {
+ if(colon <= linestart && header_buf[i]==':')
+ {
+ colon = i;
+ while(i < (endofheaders-1)
+ && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t'))
+ i++;
+ valuestart = i + 1;
+ }
+ /* detecting end of line */
+ else if(header_buf[i]=='\r' || header_buf[i]=='\n')
+ {
+ if(colon > linestart && valuestart > colon)
+ {
+#ifdef DEBUG
+ printf("header='%.*s', value='%.*s'\n",
+ colon-linestart, header_buf+linestart,
+ i-valuestart, header_buf+valuestart);
+#endif
+ if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart))
+ {
+ content_length = atoi(header_buf+valuestart);
+#ifdef DEBUG
+ printf("Content-Length: %d\n", content_length);
+#endif
+ }
+ else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart)
+ && 0==strncasecmp(header_buf+valuestart, "chunked", 7))
+ {
+#ifdef DEBUG
+ printf("chunked transfer-encoding!\n");
+#endif
+ chunked = 1;
+ }
+ }
+ while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n'))
+ i++;
+ linestart = i;
+ colon = linestart;
+ valuestart = 0;
+ }
+ }
+ /* copy the remaining of the received data back to buf */
+ n = header_buf_used - endofheaders;
+ memcpy(buf, header_buf + endofheaders, n);
+ /* if(headers) */
+ }
+ if(endofheaders)
+ {
+ /* content */
+ if(chunked)
+ {
+ int i = 0;
+ while(i < n)
+ {
+ if(chunksize == 0)
+ {
+ /* reading chunk size */
+ if(chunksize_buf_index == 0) {
+ /* skipping any leading CR LF */
+ if(i<n && buf[i] == '\r') i++;
+ if(i<n && buf[i] == '\n') i++;
+ }
+ while(i<n && isxdigit(buf[i])
+ && chunksize_buf_index < (sizeof(chunksize_buf)-1))
+ {
+ chunksize_buf[chunksize_buf_index++] = buf[i];
+ chunksize_buf[chunksize_buf_index] = '\0';
+ i++;
+ }
+ while(i<n && buf[i] != '\r' && buf[i] != '\n')
+ i++; /* discarding chunk-extension */
+ if(i<n && buf[i] == '\r') i++;
+ if(i<n && buf[i] == '\n') {
+ unsigned int j;
+ for(j = 0; j < chunksize_buf_index; j++) {
+ if(chunksize_buf[j] >= '0'
+ && chunksize_buf[j] <= '9')
+ chunksize = (chunksize << 4) + (chunksize_buf[j] - '0');
+ else
+ chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10);
+ }
+ chunksize_buf[0] = '\0';
+ chunksize_buf_index = 0;
+ i++;
+ } else {
+ /* not finished to get chunksize */
+ continue;
+ }
+#ifdef DEBUG
+ printf("chunksize = %u (%x)\n", chunksize, chunksize);
+#endif
+ if(chunksize == 0)
+ {
+#ifdef DEBUG
+ printf("end of HTTP content - %d %d\n", i, n);
+ /*printf("'%.*s'\n", n-i, buf+i);*/
+#endif
+ goto end_of_stream;
+ }
+ }
+ bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
+ if((content_buf_used + bytestocopy) > content_buf_len)
+ {
+ char * tmp;
+ if(content_length >= (int)(content_buf_used + bytestocopy)) {
+ content_buf_len = content_length;
+ } else {
+ content_buf_len = content_buf_used + bytestocopy;
+ }
+ tmp = realloc(content_buf, content_buf_len);
+ if(tmp == NULL) {
+ /* memory allocation error */
+ free(content_buf);
+ free(header_buf);
+ *size = -1;
+ return NULL;
+ }
+ content_buf = tmp;
+ }
+ memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
+ content_buf_used += bytestocopy;
+ i += bytestocopy;
+ chunksize -= bytestocopy;
+ }
+ }
+ else
+ {
+ /* not chunked */
+ if(content_length > 0
+ && (int)(content_buf_used + n) > content_length) {
+ /* skipping additional bytes */
+ n = content_length - content_buf_used;
+ }
+ if(content_buf_used + n > content_buf_len)
+ {
+ char * tmp;
+ if(content_length >= (int)(content_buf_used + n)) {
+ content_buf_len = content_length;
+ } else {
+ content_buf_len = content_buf_used + n;
+ }
+ tmp = realloc(content_buf, content_buf_len);
+ if(tmp == NULL) {
+ /* memory allocation error */
+ free(content_buf);
+ free(header_buf);
+ *size = -1;
+ return NULL;
+ }
+ content_buf = tmp;
+ }
+ memcpy(content_buf + content_buf_used, buf, n);
+ content_buf_used += n;
+ }
+ }
+ /* use the Content-Length header value if available */
+ if(content_length > 0 && (int)content_buf_used >= content_length)
+ {
+#ifdef DEBUG
+ printf("End of HTTP content\n");
+#endif
+ break;
+ }
+ }
+end_of_stream:
+ free(header_buf); header_buf = NULL;
+ *size = content_buf_used;
+ if(content_buf_used == 0)
+ {
+ free(content_buf);
+ content_buf = NULL;
+ }
+ return content_buf;
+}
+
+/* miniwget3() :
+ * do all the work.
+ * Return NULL if something failed. */
+static void *
+miniwget3(const char * host,
+ unsigned short port, const char * path,
+ int * size, char * addr_str, int addr_str_len,
+ const char * httpversion, unsigned int scope_id)
+{
+ char buf[2048];
+ int s;
+ int n;
+ int len;
+ int sent;
+ void * content;
+
+ *size = 0;
+ s = connecthostport(host, port, scope_id);
+ if(s < 0)
+ return NULL;
+
+ /* get address for caller ! */
+ if(addr_str)
+ {
+ struct sockaddr_storage saddr;
+ socklen_t saddrlen;
+
+ saddrlen = sizeof(saddr);
+ if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0)
+ {
+ perror("getsockname");
+ }
+ else
+ {
+#if defined(__amigaos__) && !defined(__amigaos4__)
+ /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
+ * But his function make a string with the port : nn.nn.nn.nn:port */
+/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
+ NULL, addr_str, (DWORD *)&addr_str_len))
+ {
+ printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
+ }*/
+ /* the following code is only compatible with ip v4 addresses */
+ strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len);
+#else
+#if 0
+ if(saddr.sa_family == AF_INET6) {
+ inet_ntop(AF_INET6,
+ &(((struct sockaddr_in6 *)&saddr)->sin6_addr),
+ addr_str, addr_str_len);
+ } else {
+ inet_ntop(AF_INET,
+ &(((struct sockaddr_in *)&saddr)->sin_addr),
+ addr_str, addr_str_len);
+ }
+#endif
+ /* getnameinfo return ip v6 address with the scope identifier
+ * such as : 2a01:e35:8b2b:7330::%4281128194 */
+ n = getnameinfo((const struct sockaddr *)&saddr, saddrlen,
+ addr_str, addr_str_len,
+ NULL, 0,
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if(n != 0) {
+#ifdef _WIN32
+ fprintf(stderr, "getnameinfo() failed : %d\n", n);
+#else
+ fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n));
+#endif
+ }
+#endif
+ }
+#ifdef DEBUG
+ printf("address miniwget : %s\n", addr_str);
+#endif
+ }
+
+ len = snprintf(buf, sizeof(buf),
+ "GET %s HTTP/%s\r\n"
+ "Host: %s:%d\r\n"
+ "Connection: Close\r\n"
+ "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
+
+ "\r\n",
+ path, httpversion, host, port);
+ if ((unsigned int)len >= sizeof(buf))
+ {
+ closesocket(s);
+ return NULL;
+ }
+ sent = 0;
+ /* sending the HTTP request */
+ while(sent < len)
+ {
+ n = send(s, buf+sent, len-sent, 0);
+ if(n < 0)
+ {
+ perror("send");
+ closesocket(s);
+ return NULL;
+ }
+ else
+ {
+ sent += n;
+ }
+ }
+ content = getHTTPResponse(s, size);
+ closesocket(s);
+ return content;
+}
+
+/* miniwget2() :
+ * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */
+static void *
+miniwget2(const char * host,
+ unsigned short port, const char * path,
+ int * size, char * addr_str, int addr_str_len,
+ unsigned int scope_id)
+{
+ char * respbuffer;
+
+#if 1
+ respbuffer = miniwget3(host, port, path, size,
+ addr_str, addr_str_len, "1.1", scope_id);
+#else
+ respbuffer = miniwget3(host, port, path, size,
+ addr_str, addr_str_len, "1.0", scope_id);
+ if (*size == 0)
+ {
+#ifdef DEBUG
+ printf("Retrying with HTTP/1.1\n");
+#endif
+ free(respbuffer);
+ respbuffer = miniwget3(host, port, path, size,
+ addr_str, addr_str_len, "1.1", scope_id);
+ }
+#endif
+ return respbuffer;
+}
+
+
+
+
+/* parseURL()
+ * arguments :
+ * url : source string not modified
+ * hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
+ * port : port (destination)
+ * path : pointer to the path part of the URL
+ *
+ * Return values :
+ * 0 - Failure
+ * 1 - Success */
+int
+parseURL(const char * url,
+ char * hostname, unsigned short * port,
+ char * * path, unsigned int * scope_id)
+{
+ char * p1, *p2, *p3;
+ if(!url)
+ return 0;
+ p1 = strstr(url, "://");
+ if(!p1)
+ return 0;
+ p1 += 3;
+ if( (url[0]!='h') || (url[1]!='t')
+ ||(url[2]!='t') || (url[3]!='p'))
+ return 0;
+ memset(hostname, 0, MAXHOSTNAMELEN + 1);
+ if(*p1 == '[')
+ {
+ /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
+ char * scope;
+ scope = strchr(p1, '%');
+ p2 = strchr(p1, ']');
+ if(p2 && scope && scope < p2 && scope_id) {
+ /* parse scope */
+#ifdef IF_NAMESIZE
+ char tmp[IF_NAMESIZE];
+ int l;
+ scope++;
+ /* "%25" is just '%' in URL encoding */
+ if(scope[0] == '2' && scope[1] == '5')
+ scope += 2; /* skip "25" */
+ l = p2 - scope;
+ if(l >= IF_NAMESIZE)
+ l = IF_NAMESIZE - 1;
+ memcpy(tmp, scope, l);
+ tmp[l] = '\0';
+ *scope_id = if_nametoindex(tmp);
+ if(*scope_id == 0) {
+ *scope_id = (unsigned int)strtoul(tmp, NULL, 10);
+ }
+#else
+ /* under windows, scope is numerical */
+ char tmp[8];
+ int l;
+ scope++;
+ /* "%25" is just '%' in URL encoding */
+ if(scope[0] == '2' && scope[1] == '5')
+ scope += 2; /* skip "25" */
+ l = p2 - scope;
+ if(l >= sizeof(tmp))
+ l = sizeof(tmp) - 1;
+ memcpy(tmp, scope, l);
+ tmp[l] = '\0';
+ *scope_id = (unsigned int)strtoul(tmp, NULL, 10);
+#endif
+ }
+ p3 = strchr(p1, '/');
+ if(p2 && p3)
+ {
+ p2++;
+ strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
+ if(*p2 == ':')
+ {
+ *port = 0;
+ p2++;
+ while( (*p2 >= '0') && (*p2 <= '9'))
+ {
+ *port *= 10;
+ *port += (unsigned short)(*p2 - '0');
+ p2++;
+ }
+ }
+ else
+ {
+ *port = 80;
+ }
+ *path = p3;
+ return 1;
+ }
+ }
+ p2 = strchr(p1, ':');
+ p3 = strchr(p1, '/');
+ if(!p3)
+ return 0;
+ if(!p2 || (p2>p3))
+ {
+ strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
+ *port = 80;
+ }
+ else
+ {
+ strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
+ *port = 0;
+ p2++;
+ while( (*p2 >= '0') && (*p2 <= '9'))
+ {
+ *port *= 10;
+ *port += (unsigned short)(*p2 - '0');
+ p2++;
+ }
+ }
+ *path = p3;
+ return 1;
+}
+
+void *
+miniwget(const char * url, int * size, unsigned int scope_id)
+{
+ unsigned short port;
+ char * path;
+ /* protocol://host:port/chemin */
+ char hostname[MAXHOSTNAMELEN+1];
+ *size = 0;
+ if(!parseURL(url, hostname, &port, &path, &scope_id))
+ return NULL;
+#ifdef DEBUG
+ printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
+ hostname, port, path, scope_id);
+#endif
+ return miniwget2(hostname, port, path, size, 0, 0, scope_id);
+}
+
+void *
+miniwget_getaddr(const char * url, int * size,
+ char * addr, int addrlen, unsigned int scope_id)
+{
+ unsigned short port;
+ char * path;
+ /* protocol://host:port/path */
+ char hostname[MAXHOSTNAMELEN+1];
+ *size = 0;
+ if(addr)
+ addr[0] = '\0';
+ if(!parseURL(url, hostname, &port, &path, &scope_id))
+ return NULL;
+#ifdef DEBUG
+ printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
+ hostname, port, path, scope_id);
+#endif
+ return miniwget2(hostname, port, path, size, addr, addrlen, scope_id);
+}
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniwget.h b/ext/miniupnpc/miniwget.h
index d6db71a8..d6db71a8 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/miniwget.h
+++ b/ext/miniupnpc/miniwget.h
diff --git a/ext/miniupnpc/minixml.c b/ext/miniupnpc/minixml.c
new file mode 100644
index 00000000..5c79b3c9
--- /dev/null
+++ b/ext/miniupnpc/minixml.c
@@ -0,0 +1,230 @@
+#define _CRT_SECURE_NO_WARNINGS
+/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */
+/* minixml.c : the minimum size a xml parser can be ! */
+/* Project : miniupnp
+ * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author : Thomas Bernard
+
+Copyright (c) 2005-2014, Thomas BERNARD
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <string.h>
+#include "minixml.h"
+
+/* parseatt : used to parse the argument list
+ * return 0 (false) in case of success and -1 (true) if the end
+ * of the xmlbuffer is reached. */
+static int parseatt(struct xmlparser * p)
+{
+ const char * attname;
+ int attnamelen;
+ const char * attvalue;
+ int attvaluelen;
+ while(p->xml < p->xmlend)
+ {
+ if(*p->xml=='/' || *p->xml=='>')
+ return 0;
+ if( !IS_WHITE_SPACE(*p->xml) )
+ {
+ char sep;
+ attname = p->xml;
+ attnamelen = 0;
+ while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
+ {
+ attnamelen++; p->xml++;
+ if(p->xml >= p->xmlend)
+ return -1;
+ }
+ while(*(p->xml++) != '=')
+ {
+ if(p->xml >= p->xmlend)
+ return -1;
+ }
+ while(IS_WHITE_SPACE(*p->xml))
+ {
+ p->xml++;
+ if(p->xml >= p->xmlend)
+ return -1;
+ }
+ sep = *p->xml;
+ if(sep=='\'' || sep=='\"')
+ {
+ p->xml++;
+ if(p->xml >= p->xmlend)
+ return -1;
+ attvalue = p->xml;
+ attvaluelen = 0;
+ while(*p->xml != sep)
+ {
+ attvaluelen++; p->xml++;
+ if(p->xml >= p->xmlend)
+ return -1;
+ }
+ }
+ else
+ {
+ attvalue = p->xml;
+ attvaluelen = 0;
+ while( !IS_WHITE_SPACE(*p->xml)
+ && *p->xml != '>' && *p->xml != '/')
+ {
+ attvaluelen++; p->xml++;
+ if(p->xml >= p->xmlend)
+ return -1;
+ }
+ }
+ /*printf("%.*s='%.*s'\n",
+ attnamelen, attname, attvaluelen, attvalue);*/
+ if(p->attfunc)
+ p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
+ }
+ p->xml++;
+ }
+ return -1;
+}
+
+/* parseelt parse the xml stream and
+ * call the callback functions when needed... */
+static void parseelt(struct xmlparser * p)
+{
+ int i;
+ const char * elementname;
+ while(p->xml < (p->xmlend - 1))
+ {
+ if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
+ {
+ p->xml += 3;
+ /* ignore comments */
+ do
+ {
+ p->xml++;
+ if ((p->xml + 3) >= p->xmlend)
+ return;
+ }
+ while(memcmp(p->xml, "-->", 3) != 0);
+ p->xml += 3;
+ }
+ else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
+ {
+ i = 0; elementname = ++p->xml;
+ while( !IS_WHITE_SPACE(*p->xml)
+ && (*p->xml!='>') && (*p->xml!='/')
+ )
+ {
+ i++; p->xml++;
+ if (p->xml >= p->xmlend)
+ return;
+ /* to ignore namespace : */
+ if(*p->xml==':')
+ {
+ i = 0;
+ elementname = ++p->xml;
+ }
+ }
+ if(i>0)
+ {
+ if(p->starteltfunc)
+ p->starteltfunc(p->data, elementname, i);
+ if(parseatt(p))
+ return;
+ if(*p->xml!='/')
+ {
+ const char * data;
+ i = 0; data = ++p->xml;
+ if (p->xml >= p->xmlend)
+ return;
+ while( IS_WHITE_SPACE(*p->xml) )
+ {
+ i++; p->xml++;
+ if (p->xml >= p->xmlend)
+ return;
+ }
+ if(memcmp(p->xml, "<![CDATA[", 9) == 0)
+ {
+ /* CDATA handling */
+ p->xml += 9;
+ data = p->xml;
+ i = 0;
+ while(memcmp(p->xml, "]]>", 3) != 0)
+ {
+ i++; p->xml++;
+ if ((p->xml + 3) >= p->xmlend)
+ return;
+ }
+ if(i>0 && p->datafunc)
+ p->datafunc(p->data, data, i);
+ while(*p->xml!='<')
+ {
+ p->xml++;
+ if (p->xml >= p->xmlend)
+ return;
+ }
+ }
+ else
+ {
+ while(*p->xml!='<')
+ {
+ i++; p->xml++;
+ if ((p->xml + 1) >= p->xmlend)
+ return;
+ }
+ if(i>0 && p->datafunc && *(p->xml + 1) == '/')
+ p->datafunc(p->data, data, i);
+ }
+ }
+ }
+ else if(*p->xml == '/')
+ {
+ i = 0; elementname = ++p->xml;
+ if (p->xml >= p->xmlend)
+ return;
+ while((*p->xml != '>'))
+ {
+ i++; p->xml++;
+ if (p->xml >= p->xmlend)
+ return;
+ }
+ if(p->endeltfunc)
+ p->endeltfunc(p->data, elementname, i);
+ p->xml++;
+ }
+ }
+ else
+ {
+ p->xml++;
+ }
+ }
+}
+
+/* the parser must be initialized before calling this function */
+void parsexml(struct xmlparser * parser)
+{
+ parser->xml = parser->xmlstart;
+ parser->xmlend = parser->xmlstart + parser->xmlsize;
+ parseelt(parser);
+}
+
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/minixml.h b/ext/miniupnpc/minixml.h
index 9f43aa48..9f43aa48 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/minixml.h
+++ b/ext/miniupnpc/minixml.h
diff --git a/ext/miniupnpc/minixmlvalid.c b/ext/miniupnpc/minixmlvalid.c
new file mode 100644
index 00000000..a86beba8
--- /dev/null
+++ b/ext/miniupnpc/minixmlvalid.c
@@ -0,0 +1,164 @@
+#define _CRT_SECURE_NO_WARNINGS
+/* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */
+/* MiniUPnP Project
+ * http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
+ * minixmlvalid.c :
+ * validation program for the minixml parser
+ *
+ * (c) 2006-2011 Thomas Bernard */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "minixml.h"
+
+/* xml event structure */
+struct event {
+ enum { ELTSTART, ELTEND, ATT, CHARDATA } type;
+ const char * data;
+ int len;
+};
+
+struct eventlist {
+ int n;
+ struct event * events;
+};
+
+/* compare 2 xml event lists
+ * return 0 if the two lists are equals */
+int evtlistcmp(struct eventlist * a, struct eventlist * b)
+{
+ int i;
+ struct event * ae, * be;
+ if(a->n != b->n)
+ {
+ printf("event number not matching : %d != %d\n", a->n, b->n);
+ /*return 1;*/
+ }
+ for(i=0; i<a->n; i++)
+ {
+ ae = a->events + i;
+ be = b->events + i;
+ if( (ae->type != be->type)
+ ||(ae->len != be->len)
+ ||memcmp(ae->data, be->data, ae->len))
+ {
+ printf("Found a difference : %d '%.*s' != %d '%.*s'\n",
+ ae->type, ae->len, ae->data,
+ be->type, be->len, be->data);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Test data */
+static const char xmldata[] =
+"<xmlroot>\n"
+" <elt1 att1=\"attvalue1\" att2=\"attvalue2\">"
+"character data"
+"</elt1> \n \t"
+"<elt1b/>"
+"<elt1>\n<![CDATA[ <html>stuff !\n ]]> \n</elt1>\n"
+"<elt2a> \t<elt2b>chardata1</elt2b><elt2b> chardata2 </elt2b></elt2a>"
+"</xmlroot>";
+
+static const struct event evtref[] =
+{
+ {ELTSTART, "xmlroot", 7},
+ {ELTSTART, "elt1", 4},
+ /* attributes */
+ {CHARDATA, "character data", 14},
+ {ELTEND, "elt1", 4},
+ {ELTSTART, "elt1b", 5},
+ {ELTSTART, "elt1", 4},
+ {CHARDATA, " <html>stuff !\n ", 16},
+ {ELTEND, "elt1", 4},
+ {ELTSTART, "elt2a", 5},
+ {ELTSTART, "elt2b", 5},
+ {CHARDATA, "chardata1", 9},
+ {ELTEND, "elt2b", 5},
+ {ELTSTART, "elt2b", 5},
+ {CHARDATA, " chardata2 ", 11},
+ {ELTEND, "elt2b", 5},
+ {ELTEND, "elt2a", 5},
+ {ELTEND, "xmlroot", 7}
+};
+
+void startelt(void * data, const char * p, int l)
+{
+ struct eventlist * evtlist = data;
+ struct event * evt;
+ evt = evtlist->events + evtlist->n;
+ /*printf("startelt : %.*s\n", l, p);*/
+ evt->type = ELTSTART;
+ evt->data = p;
+ evt->len = l;
+ evtlist->n++;
+}
+
+void endelt(void * data, const char * p, int l)
+{
+ struct eventlist * evtlist = data;
+ struct event * evt;
+ evt = evtlist->events + evtlist->n;
+ /*printf("endelt : %.*s\n", l, p);*/
+ evt->type = ELTEND;
+ evt->data = p;
+ evt->len = l;
+ evtlist->n++;
+}
+
+void chardata(void * data, const char * p, int l)
+{
+ struct eventlist * evtlist = data;
+ struct event * evt;
+ evt = evtlist->events + evtlist->n;
+ /*printf("chardata : '%.*s'\n", l, p);*/
+ evt->type = CHARDATA;
+ evt->data = p;
+ evt->len = l;
+ evtlist->n++;
+}
+
+int testxmlparser(const char * xml, int size)
+{
+ int r;
+ struct eventlist evtlist;
+ struct eventlist evtlistref;
+ struct xmlparser parser;
+ evtlist.n = 0;
+ evtlist.events = malloc(sizeof(struct event)*100);
+ if(evtlist.events == NULL)
+ {
+ fprintf(stderr, "Memory allocation error.\n");
+ return -1;
+ }
+ memset(&parser, 0, sizeof(parser));
+ parser.xmlstart = xml;
+ parser.xmlsize = size;
+ parser.data = &evtlist;
+ parser.starteltfunc = startelt;
+ parser.endeltfunc = endelt;
+ parser.datafunc = chardata;
+ parsexml(&parser);
+ printf("%d events\n", evtlist.n);
+ /* compare */
+ evtlistref.n = sizeof(evtref)/sizeof(struct event);
+ evtlistref.events = (struct event *)evtref;
+ r = evtlistcmp(&evtlistref, &evtlist);
+ free(evtlist.events);
+ return r;
+}
+
+int main(int argc, char * * argv)
+{
+ int r;
+ (void)argc; (void)argv;
+
+ r = testxmlparser(xmldata, sizeof(xmldata)-1);
+ if(r)
+ printf("minixml validation test failed\n");
+ return r;
+}
+
diff --git a/ext/miniupnpc/msvc/miniupnpc.sln b/ext/miniupnpc/msvc/miniupnpc.sln
new file mode 100644
index 00000000..b3da1919
--- /dev/null
+++ b/ext/miniupnpc/msvc/miniupnpc.sln
@@ -0,0 +1,29 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "miniupnpc.vcproj", "{D28CE435-CB33-4BAE-8A52-C6EF915956F5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upnpc-static", "upnpc-static.vcproj", "{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D28CE435-CB33-4BAE-8A52-C6EF915956F5} = {D28CE435-CB33-4BAE-8A52-C6EF915956F5}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.Build.0 = Debug|Win32
+ {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.ActiveCfg = Release|Win32
+ {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.Build.0 = Release|Win32
+ {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.Build.0 = Debug|Win32
+ {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.ActiveCfg = Release|Win32
+ {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/ext/miniupnpc/msvc/miniupnpc.vcproj b/ext/miniupnpc/msvc/miniupnpc.vcproj
new file mode 100644
index 00000000..fb301e3b
--- /dev/null
+++ b/ext/miniupnpc/msvc/miniupnpc.vcproj
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="miniupnpc"
+ ProjectGUID="{D28CE435-CB33-4BAE-8A52-C6EF915956F5}"
+ RootNamespace="miniupnpc"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;DEBUG"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Fichiers sources"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\connecthostport.c"
+ >
+ </File>
+ <File
+ RelativePath="..\igd_desc_parse.c"
+ >
+ </File>
+ <File
+ RelativePath="..\minisoap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\minissdpc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\miniupnpc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\miniwget.c"
+ >
+ </File>
+ <File
+ RelativePath="..\minixml.c"
+ >
+ </File>
+ <File
+ RelativePath="..\portlistingparse.c"
+ >
+ </File>
+ <File
+ RelativePath="..\receivedata.c"
+ >
+ </File>
+ <File
+ RelativePath="..\upnpcommands.c"
+ >
+ </File>
+ <File
+ RelativePath="..\upnpdev.c"
+ >
+ </File>
+ <File
+ RelativePath="..\upnperrors.c"
+ >
+ </File>
+ <File
+ RelativePath="..\upnpreplyparse.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Fichiers d&apos;en-tête"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\connecthostport.h"
+ >
+ </File>
+ <File
+ RelativePath="..\declspec.h"
+ >
+ </File>
+ <File
+ RelativePath="..\igd_desc_parse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\minisoap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\minissdpc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\miniupnpc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\miniupnpcstrings.h"
+ >
+ </File>
+ <File
+ RelativePath="..\miniupnpctypes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\miniwget.h"
+ >
+ </File>
+ <File
+ RelativePath="..\minixml.h"
+ >
+ </File>
+ <File
+ RelativePath="..\portlistingparse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\receivedata.h"
+ >
+ </File>
+ <File
+ RelativePath="..\upnpcommands.h"
+ >
+ </File>
+ <File
+ RelativePath="..\upnpdev.h"
+ >
+ </File>
+ <File
+ RelativePath="..\upnperrors.h"
+ >
+ </File>
+ <File
+ RelativePath="..\upnpreplyparse.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Fichiers de ressources"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/ext/miniupnpc/msvc/upnpc-static.vcproj b/ext/miniupnpc/msvc/upnpc-static.vcproj
new file mode 100644
index 00000000..c88c9a6e
--- /dev/null
+++ b/ext/miniupnpc/msvc/upnpc-static.vcproj
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="upnpc-static"
+ ProjectGUID="{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}"
+ RootNamespace="upnpcstatic"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE;MINIUPNP_STATICLIB;DEBUG;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib IPHlpApi.Lib Debug\miniupnpc.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib IPHlpApi.Lib Release\miniupnpc.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Fichiers sources"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\upnpc.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Fichiers d&apos;en-tête"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Fichiers de ressources"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/ext/miniupnpc/portlistingparse.c b/ext/miniupnpc/portlistingparse.c
new file mode 100644
index 00000000..0e092780
--- /dev/null
+++ b/ext/miniupnpc/portlistingparse.c
@@ -0,0 +1,172 @@
+/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */
+/* MiniUPnP project
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * (c) 2011-2015 Thomas Bernard
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+#include <string.h>
+#include <stdlib.h>
+#ifdef DEBUG
+#include <stdio.h>
+#endif /* DEBUG */
+#include "portlistingparse.h"
+#include "minixml.h"
+
+/* list of the elements */
+static const struct {
+ const portMappingElt code;
+ const char * const str;
+} elements[] = {
+ { PortMappingEntry, "PortMappingEntry"},
+ { NewRemoteHost, "NewRemoteHost"},
+ { NewExternalPort, "NewExternalPort"},
+ { NewProtocol, "NewProtocol"},
+ { NewInternalPort, "NewInternalPort"},
+ { NewInternalClient, "NewInternalClient"},
+ { NewEnabled, "NewEnabled"},
+ { NewDescription, "NewDescription"},
+ { NewLeaseTime, "NewLeaseTime"},
+ { PortMappingEltNone, NULL}
+};
+
+/* Helper function */
+static UNSIGNED_INTEGER
+atoui(const char * p, int l)
+{
+ UNSIGNED_INTEGER r = 0;
+ while(l > 0 && *p)
+ {
+ if(*p >= '0' && *p <= '9')
+ r = r*10 + (*p - '0');
+ else
+ break;
+ p++;
+ l--;
+ }
+ return r;
+}
+
+/* Start element handler */
+static void
+startelt(void * d, const char * name, int l)
+{
+ int i;
+ struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
+ pdata->curelt = PortMappingEltNone;
+ for(i = 0; elements[i].str; i++)
+ {
+ if(memcmp(name, elements[i].str, l) == 0)
+ {
+ pdata->curelt = elements[i].code;
+ break;
+ }
+ }
+ if(pdata->curelt == PortMappingEntry)
+ {
+ struct PortMapping * pm;
+ pm = calloc(1, sizeof(struct PortMapping));
+ if(pm == NULL)
+ {
+ /* malloc error */
+#ifdef DEBUG
+ fprintf(stderr, "%s: error allocating memory",
+ "startelt");
+#endif /* DEBUG */
+ return;
+ }
+ pm->l_next = pdata->l_head; /* insert in list */
+ pdata->l_head = pm;
+ }
+}
+
+/* End element handler */
+static void
+endelt(void * d, const char * name, int l)
+{
+ struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
+ (void)name;
+ (void)l;
+ pdata->curelt = PortMappingEltNone;
+}
+
+/* Data handler */
+static void
+data(void * d, const char * data, int l)
+{
+ struct PortMapping * pm;
+ struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
+ pm = pdata->l_head;
+ if(!pm)
+ return;
+ if(l > 63)
+ l = 63;
+ switch(pdata->curelt)
+ {
+ case NewRemoteHost:
+ memcpy(pm->remoteHost, data, l);
+ pm->remoteHost[l] = '\0';
+ break;
+ case NewExternalPort:
+ pm->externalPort = (unsigned short)atoui(data, l);
+ break;
+ case NewProtocol:
+ if(l > 3)
+ l = 3;
+ memcpy(pm->protocol, data, l);
+ pm->protocol[l] = '\0';
+ break;
+ case NewInternalPort:
+ pm->internalPort = (unsigned short)atoui(data, l);
+ break;
+ case NewInternalClient:
+ memcpy(pm->internalClient, data, l);
+ pm->internalClient[l] = '\0';
+ break;
+ case NewEnabled:
+ pm->enabled = (unsigned char)atoui(data, l);
+ break;
+ case NewDescription:
+ memcpy(pm->description, data, l);
+ pm->description[l] = '\0';
+ break;
+ case NewLeaseTime:
+ pm->leaseTime = atoui(data, l);
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* Parse the PortMappingList XML document for IGD version 2
+ */
+void
+ParsePortListing(const char * buffer, int bufsize,
+ struct PortMappingParserData * pdata)
+{
+ struct xmlparser parser;
+
+ memset(pdata, 0, sizeof(struct PortMappingParserData));
+ /* init xmlparser */
+ parser.xmlstart = buffer;
+ parser.xmlsize = bufsize;
+ parser.data = pdata;
+ parser.starteltfunc = startelt;
+ parser.endeltfunc = endelt;
+ parser.datafunc = data;
+ parser.attfunc = 0;
+ parsexml(&parser);
+}
+
+void
+FreePortListing(struct PortMappingParserData * pdata)
+{
+ struct PortMapping * pm;
+ while((pm = pdata->l_head) != NULL)
+ {
+ /* remove from list */
+ pdata->l_head = pm->l_next;
+ free(pm);
+ }
+}
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h b/ext/miniupnpc/portlistingparse.h
index 661ad1fa..661ad1fa 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h
+++ b/ext/miniupnpc/portlistingparse.h
diff --git a/ext/miniupnpc/pymoduletest.py b/ext/miniupnpc/pymoduletest.py
new file mode 100644
index 00000000..9fddd9c2
--- /dev/null
+++ b/ext/miniupnpc/pymoduletest.py
@@ -0,0 +1,88 @@
+#! /usr/bin/python
+# vim: tabstop=2 shiftwidth=2 expandtab
+# MiniUPnP project
+# Author : Thomas Bernard
+# This Sample code is public domain.
+# website : http://miniupnp.tuxfamily.org/
+
+# import the python miniupnpc module
+import miniupnpc
+import sys
+
+try:
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-m', '--multicastif')
+ parser.add_argument('-p', '--minissdpdsocket')
+ parser.add_argument('-d', '--discoverdelay', type=int, default=200)
+ parser.add_argument('-z', '--localport', type=int, default=0)
+ # create the object
+ u = miniupnpc.UPnP(**vars(parser.parse_args()))
+except:
+ print 'argparse not available'
+ i = 1
+ multicastif = None
+ minissdpdsocket = None
+ discoverdelay = 200
+ localport = 0
+ while i < len(sys.argv):
+ print sys.argv[i]
+ if sys.argv[i] == '-m' or sys.argv[i] == '--multicastif':
+ multicastif = sys.argv[i+1]
+ elif sys.argv[i] == '-p' or sys.argv[i] == '--minissdpdsocket':
+ minissdpdsocket = sys.argv[i+1]
+ elif sys.argv[i] == '-d' or sys.argv[i] == '--discoverdelay':
+ discoverdelay = int(sys.argv[i+1])
+ elif sys.argv[i] == '-z' or sys.argv[i] == '--localport':
+ localport = int(sys.argv[i+1])
+ else:
+ raise Exception('invalid argument %s' % sys.argv[i])
+ i += 2
+ # create the object
+ u = miniupnpc.UPnP(multicastif, minissdpdsocket, discoverdelay, localport)
+
+print 'inital(default) values :'
+print ' discoverdelay', u.discoverdelay
+print ' lanaddr', u.lanaddr
+print ' multicastif', u.multicastif
+print ' minissdpdsocket', u.minissdpdsocket
+#u.minissdpdsocket = '../minissdpd/minissdpd.sock'
+# discovery process, it usualy takes several seconds (2 seconds or more)
+print 'Discovering... delay=%ums' % u.discoverdelay
+print u.discover(), 'device(s) detected'
+# select an igd
+try:
+ u.selectigd()
+except Exception, e:
+ print 'Exception :', e
+ sys.exit(1)
+# display information about the IGD and the internet connection
+print 'local ip address :', u.lanaddr
+print 'external ip address :', u.externalipaddress()
+print u.statusinfo(), u.connectiontype()
+print 'total bytes : sent', u.totalbytesent(), 'received', u.totalbytereceived()
+print 'total packets : sent', u.totalpacketsent(), 'received', u.totalpacketreceived()
+
+#print u.addportmapping(64000, 'TCP',
+# '192.168.1.166', 63000, 'port mapping test', '')
+#print u.deleteportmapping(64000, 'TCP')
+
+port = 0
+proto = 'UDP'
+# list the redirections :
+i = 0
+while True:
+ p = u.getgenericportmapping(i)
+ if p==None:
+ break
+ print i, p
+ (port, proto, (ihost,iport), desc, c, d, e) = p
+ #print port, desc
+ i = i + 1
+
+print u.getspecificportmapping(port, proto)
+try:
+ print u.getportmappingnumberofentries()
+except Exception, e:
+ print 'GetPortMappingNumberOfEntries() is not supported :', e
+
diff --git a/ext/miniupnpc/receivedata.c b/ext/miniupnpc/receivedata.c
new file mode 100644
index 00000000..fb05e09d
--- /dev/null
+++ b/ext/miniupnpc/receivedata.c
@@ -0,0 +1,105 @@
+/* $Id: receivedata.c,v 1.6 2014/11/13 13:51:52 nanard Exp $ */
+/* Project : miniupnp
+ * Website : http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2011-2014 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution. */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else /* _WIN32 */
+#include <unistd.h>
+#if defined(__amigaos__) && !defined(__amigaos4__)
+#define socklen_t int
+#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
+#include <sys/select.h>
+#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#if !defined(__amigaos__) && !defined(__amigaos4__)
+#include <poll.h>
+#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */
+#include <errno.h>
+#define MINIUPNPC_IGNORE_EINTR
+#endif /* _WIN32 */
+
+#ifdef _WIN32
+#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
+#else
+#define PRINT_SOCKET_ERROR(x) perror(x)
+#endif
+
+#include "receivedata.h"
+
+int
+receivedata(int socket,
+ char * data, int length,
+ int timeout, unsigned int * scope_id)
+{
+#if MINIUPNPC_GET_SRC_ADDR
+ struct sockaddr_storage src_addr;
+ socklen_t src_addr_len = sizeof(src_addr);
+#endif /* MINIUPNPC_GET_SRC_ADDR */
+ int n;
+#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
+ /* using poll */
+ struct pollfd fds[1]; /* for the poll */
+#ifdef MINIUPNPC_IGNORE_EINTR
+ do {
+#endif /* MINIUPNPC_IGNORE_EINTR */
+ fds[0].fd = socket;
+ fds[0].events = POLLIN;
+ n = poll(fds, 1, timeout);
+#ifdef MINIUPNPC_IGNORE_EINTR
+ } while(n < 0 && errno == EINTR);
+#endif /* MINIUPNPC_IGNORE_EINTR */
+ if(n < 0) {
+ PRINT_SOCKET_ERROR("poll");
+ return -1;
+ } else if(n == 0) {
+ /* timeout */
+ return 0;
+ }
+#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
+ /* using select under _WIN32 and amigaos */
+ fd_set socketSet;
+ TIMEVAL timeval;
+ FD_ZERO(&socketSet);
+ FD_SET(socket, &socketSet);
+ timeval.tv_sec = timeout / 1000;
+ timeval.tv_usec = (timeout % 1000) * 1000;
+ n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
+ if(n < 0) {
+ PRINT_SOCKET_ERROR("select");
+ return -1;
+ } else if(n == 0) {
+ return 0;
+ }
+#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
+#if MINIUPNPC_GET_SRC_ADDR
+ memset(&src_addr, 0, sizeof(src_addr));
+ n = recvfrom(socket, data, length, 0,
+ (struct sockaddr *)&src_addr, &src_addr_len);
+#else /* MINIUPNPC_GET_SRC_ADDR */
+ n = recv(socket, data, length, 0);
+#endif /* MINIUPNPC_GET_SRC_ADDR */
+ if(n<0) {
+ PRINT_SOCKET_ERROR("recv");
+ }
+#if MINIUPNPC_GET_SRC_ADDR
+ if (src_addr.ss_family == AF_INET6) {
+ const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr;
+#ifdef DEBUG
+ printf("scope_id=%u\n", src_addr6->sin6_scope_id);
+#endif /* DEBUG */
+ if(scope_id)
+ *scope_id = src_addr6->sin6_scope_id;
+ }
+#endif /* MINIUPNPC_GET_SRC_ADDR */
+ return n;
+}
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/receivedata.h b/ext/miniupnpc/receivedata.h
index 0520a11d..0520a11d 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/receivedata.h
+++ b/ext/miniupnpc/receivedata.h
diff --git a/ext/miniupnpc/setup.py b/ext/miniupnpc/setup.py
new file mode 100644
index 00000000..97e42bf1
--- /dev/null
+++ b/ext/miniupnpc/setup.py
@@ -0,0 +1,28 @@
+#! /usr/bin/python
+# vim: tabstop=8 shiftwidth=8 expandtab
+# $Id: setup.py,v 1.12 2015/10/26 17:03:17 nanard Exp $
+# the MiniUPnP Project (c) 2007-2014 Thomas Bernard
+# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
+#
+# python script to build the miniupnpc module under unix
+#
+# replace libminiupnpc.a by libminiupnpc.so for shared library usage
+try:
+ from setuptools import setup, Extension
+except ImportError:
+ from distutils.core import setup, Extension
+from distutils import sysconfig
+sysconfig.get_config_vars()["OPT"] = ''
+sysconfig.get_config_vars()["CFLAGS"] = ''
+setup(name="miniupnpc",
+ version=open('VERSION').read().strip(),
+ author='Thomas BERNARD',
+ author_email='miniupnp@free.fr',
+ license=open('LICENSE').read(),
+ url='http://miniupnp.free.fr/',
+ description='miniUPnP client',
+ ext_modules=[
+ Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
+ extra_objects=["libminiupnpc.a"])
+ ])
+
diff --git a/ext/miniupnpc/setupmingw32.py b/ext/miniupnpc/setupmingw32.py
new file mode 100644
index 00000000..43dfb465
--- /dev/null
+++ b/ext/miniupnpc/setupmingw32.py
@@ -0,0 +1,28 @@
+#! /usr/bin/python
+# vim: tabstop=8 shiftwidth=8 expandtab
+# $Id: setupmingw32.py,v 1.10 2015/10/26 17:03:17 nanard Exp $
+# the MiniUPnP Project (c) 2007-2014 Thomas Bernard
+# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
+#
+# python script to build the miniupnpc module under windows (using mingw32)
+#
+try:
+ from setuptools import setup, Extension
+except ImportError:
+ from distutils.core import setup, Extension
+from distutils import sysconfig
+sysconfig.get_config_vars()["OPT"] = ''
+sysconfig.get_config_vars()["CFLAGS"] = ''
+setup(name="miniupnpc",
+ version=open('VERSION').read().strip(),
+ author='Thomas BERNARD',
+ author_email='miniupnp@free.fr',
+ license=open('LICENSE').read(),
+ url='http://miniupnp.free.fr/',
+ description='miniUPnP client',
+ ext_modules=[
+ Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
+ libraries=["ws2_32", "iphlpapi"],
+ extra_objects=["libminiupnpc.a"])
+ ])
+
diff --git a/ext/miniupnpc/testdesc/linksys_WAG200G_desc.values b/ext/miniupnpc/testdesc/linksys_WAG200G_desc.values
new file mode 100644
index 00000000..cf422218
--- /dev/null
+++ b/ext/miniupnpc/testdesc/linksys_WAG200G_desc.values
@@ -0,0 +1,14 @@
+# values for linksys_WAG200G_desc.xml
+
+CIF:
+ servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
+ controlurl = /upnp/control/WANCommonIFC1
+ eventsuburl = /upnp/event/WANCommonIFC1
+ scpdurl = /cmnicfg.xml
+
+first:
+ servicetype = urn:schemas-upnp-org:service:WANPPPConnection:1
+ controlurl = /upnp/control/WANPPPConn1
+ eventsuburl = /upnp/event/WANPPPConn1
+ scpdurl = /pppcfg.xml
+
diff --git a/ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml b/ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml
new file mode 100644
index 00000000..d428d73b
--- /dev/null
+++ b/ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0"?>
+<root xmlns="urn:schemas-upnp-org:device-1-0">
+<specVersion>
+<major>1</major>
+<minor>0</minor>
+</specVersion>
+<URLBase>http://192.168.1.1:49152</URLBase>
+<device>
+<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
+<friendlyName>LINKSYS WAG200G Gateway</friendlyName>
+<manufacturer>LINKSYS</manufacturer>
+<manufacturerURL>http://www.linksys.com</manufacturerURL>
+<modelDescription>LINKSYS WAG200G Gateway</modelDescription>
+<modelName>Wireless-G ADSL Home Gateway</modelName>
+<modelNumber>WAG200G</modelNumber>
+<modelURL>http://www.linksys.com</modelURL>
+<serialNumber>123456789</serialNumber>
+<UDN>uuid:8ca2eb37-1dd2-11b2-86f1-001a709b5aa8</UDN>
+<UPC>WAG200G</UPC>
+<serviceList>
+<service>
+<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
+<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>
+<controlURL>/upnp/control/L3Forwarding1</controlURL>
+<eventSubURL>/upnp/event/L3Forwarding1</eventSubURL>
+<SCPDURL>/l3frwd.xml</SCPDURL>
+</service>
+</serviceList>
+<deviceList>
+<device>
+<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>
+<friendlyName>WANDevice</friendlyName>
+<manufacturer>LINKSYS</manufacturer>
+<manufacturerURL>http://www.linksys.com/</manufacturerURL>
+<modelDescription>Residential Gateway</modelDescription>
+<modelName>Internet Connection Sharing</modelName>
+<modelNumber>1</modelNumber>
+<modelURL>http://www.linksys.com/</modelURL>
+<serialNumber>0000001</serialNumber>
+<UDN>uuid:8ca2eb36-1dd2-11b2-86f1-001a709b5aa8</UDN>
+<UPC>WAG200G</UPC>
+<serviceList>
+<service>
+<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
+<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
+<controlURL>/upnp/control/WANCommonIFC1</controlURL>
+<eventSubURL>/upnp/event/WANCommonIFC1</eventSubURL>
+<SCPDURL>/cmnicfg.xml</SCPDURL>
+</service>
+</serviceList>
+<deviceList>
+<device>
+<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
+<friendlyName>WANConnectionDevice</friendlyName>
+<manufacturer>LINKSYS</manufacturer>
+<manufacturerURL>http://www.linksys.com/</manufacturerURL>
+<modelDescription>Residential Gateway</modelDescription>
+<modelName>Internet Connection Sharing</modelName>
+<modelNumber>1</modelNumber>
+<modelURL>http://www.linksys.com/</modelURL>
+<serialNumber>0000001</serialNumber>
+<UDN>uuid:8ca2eb37-1dd2-11b2-86f0-001a709b5aa8</UDN>
+<UPC>WAG200G</UPC>
+<serviceList>
+<service>
+<serviceType>urn:schemas-upnp-org:service:WANEthernetLinkConfig:1</serviceType>
+<serviceId>urn:upnp-org:serviceId:WANEthLinkC1</serviceId>
+<controlURL>/upnp/control/WANEthLinkC1</controlURL>
+<eventSubURL>/upnp/event/WANEthLinkC1</eventSubURL>
+<SCPDURL>/wanelcfg.xml</SCPDURL>
+</service>
+<service>
+<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType>
+<serviceId>urn:upnp-org:serviceId:WANPPPConn1</serviceId>
+<controlURL>/upnp/control/WANPPPConn1</controlURL>
+<eventSubURL>/upnp/event/WANPPPConn1</eventSubURL>
+<SCPDURL>/pppcfg.xml</SCPDURL>
+</service>
+</serviceList>
+</device>
+</deviceList>
+</device>
+<device>
+<deviceType>urn:schemas-upnp-org:device:LANDevice:1</deviceType>
+<friendlyName>LANDevice</friendlyName>
+<manufacturer>LINKSYS</manufacturer>
+<manufacturerURL>http://www.linksys.com/</manufacturerURL>
+<modelDescription>Residential Gateway</modelDescription>
+<modelName>Residential Gateway</modelName>
+<modelNumber>1</modelNumber>
+<modelURL>http://www.linksys.com/</modelURL>
+<serialNumber>0000001</serialNumber>
+<UDN>uuid:8ca2eb36-1dd2-11b2-86f0-001a709b5aa
+8</UDN>
+<UPC>WAG200G</UPC>
+<serviceList>
+<service>
+<serviceType>urn:schemas-upnp-org:service:LANHostConfigManagement:1</serviceType>
+<serviceId>urn:upnp-org:serviceId:LANHostCfg1</serviceId>
+<controlURL>/upnp/control/LANHostCfg1</controlURL>
+<eventSubURL>/upnp/event/LANHostCfg1</eventSubURL>
+<SCPDURL>/lanhostc.xml</SCPDURL>
+</service>
+</serviceList>
+</device>
+</deviceList>
+<presentationURL>http://192.168.1.1/index.htm</presentationURL>
+</device>
+</root>
+
diff --git a/ext/miniupnpc/testdesc/new_LiveBox_desc.values b/ext/miniupnpc/testdesc/new_LiveBox_desc.values
new file mode 100644
index 00000000..c55552e5
--- /dev/null
+++ b/ext/miniupnpc/testdesc/new_LiveBox_desc.values
@@ -0,0 +1,20 @@
+# values for new_LiveBox_desc.xml
+
+CIF:
+ servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
+ controlurl = /87895a19/upnp/control/WANCommonIFC1
+ eventsuburl = /87895a19/upnp/control/WANCommonIFC1
+ scpdurl = /87895a19/gateicfgSCPD.xml
+
+first:
+ servicetype = urn:schemas-upnp-org:service:WANPPPConnection:2
+ controlurl = /87895a19/upnp/control/WANIPConn1
+ eventsuburl = /87895a19/upnp/control/WANIPConn1
+ scpdurl = /87895a19/gateconnSCPD_PPP.xml
+
+IPv6FC:
+ servicetype = urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
+ controlurl = /87895a19/upnp/control/WANIPv6FwCtrl1
+ eventsuburl = /87895a19/upnp/control/WANIPv6FwCtrl1
+ scpdurl = /87895a19/wanipv6fwctrlSCPD.xml
+
diff --git a/ext/miniupnpc/testdesc/new_LiveBox_desc.xml b/ext/miniupnpc/testdesc/new_LiveBox_desc.xml
new file mode 100644
index 00000000..620eb55a
--- /dev/null
+++ b/ext/miniupnpc/testdesc/new_LiveBox_desc.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<root xmlns="urn:schemas-upnp-org:device-1-0">
+ <specVersion>
+ <major>1</major>
+ <minor>0</minor>
+ </specVersion>
+ <device>
+ <pnpx:X_hardwareId xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">VEN_0129&amp;DEV_0000&amp;SUBSYS_03&amp;REV_250417</pnpx:X_hardwareId>
+ <pnpx:X_compatibleId xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">GenericUmPass</pnpx:X_compatibleId>
+ <pnpx:X_deviceCategory xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">NetworkInfrastructure.Gateway</pnpx:X_deviceCategory>
+ <df:X_deviceCategory xmlns:df="http://schemas.microsoft.com/windows/2008/09/devicefoundation">Network.Gateway</df:X_deviceCategory>
+ <deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:2</deviceType>
+ <friendlyName>Orange Livebox</friendlyName>
+ <manufacturer>Sagemcom</manufacturer>
+ <manufacturerURL>http://www.sagemcom.com/</manufacturerURL>
+ <modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName>
+ <UDN>uuid:87895a19-50f9-3736-a87f-115c230155f8</UDN>
+ <modelDescription>Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription>
+ <modelNumber>3</modelNumber>
+ <serialNumber>LK14129DP441489</serialNumber>
+ <presentationURL>http://192.168.1.1</presentationURL>
+ <UPC></UPC>
+ <iconList>
+ <icon>
+ <mimetype>image/png</mimetype>
+ <width>16</width>
+ <height>16</height>
+ <depth>8</depth>
+ <url>/87895a19/ligd.png</url>
+ </icon>
+ </iconList>
+ <deviceList>
+ <device>
+ <deviceType>urn:schemas-upnp-org:device:WANDevice:2</deviceType>
+ <friendlyName>WANDevice</friendlyName>
+ <manufacturer>Sagemcom</manufacturer>
+ <manufacturerURL>http://www.sagemcom.com/</manufacturerURL>
+ <modelDescription>WAN Device on Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription>
+ <modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName>
+ <modelNumber>3</modelNumber>
+ <modelURL>http://www.sagemcom.com/</modelURL>
+ <serialNumber>LK14129DP441489</serialNumber>
+ <presentationURL>http://192.168.1.1</presentationURL>
+ <UDN>uuid:e2397374-53d8-3fc6-8306-593ba1a34625</UDN>
+ <UPC></UPC>
+ <serviceList>
+ <service>
+ <serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
+ <serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
+ <controlURL>/87895a19/upnp/control/WANCommonIFC1</controlURL>
+ <eventSubURL>/87895a19/upnp/control/WANCommonIFC1</eventSubURL>
+ <SCPDURL>/87895a19/gateicfgSCPD.xml</SCPDURL>
+ </service>
+ </serviceList>
+ <deviceList>
+ <device>
+ <deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:2</deviceType>
+ <friendlyName>WANConnectionDevice</friendlyName>
+ <manufacturer>Sagemcom</manufacturer>
+ <manufacturerURL>http://www.sagemcom.com/</manufacturerURL>
+ <modelDescription>WanConnectionDevice on Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription>
+ <modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName>
+ <modelNumber>3</modelNumber>
+ <modelURL>http://www.sagemcom.com/</modelURL>
+ <serialNumber>LK14129DP441489</serialNumber>
+ <presentationURL>http://192.168.1.1</presentationURL>
+ <UDN>uuid:44598a08-288e-32c9-8a4d-d3c008ede331</UDN>
+ <UPC></UPC>
+ <serviceList>
+ <service>
+ <serviceType>urn:schemas-upnp-org:service:WANPPPConnection:2</serviceType>
+ <serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
+ <controlURL>/87895a19/upnp/control/WANIPConn1</controlURL>
+ <eventSubURL>/87895a19/upnp/control/WANIPConn1</eventSubURL>
+ <SCPDURL>/87895a19/gateconnSCPD_PPP.xml</SCPDURL>
+ </service>
+ <service>
+ <serviceType>urn:schemas-upnp-org:service:WANIPv6FirewallControl:1</serviceType>
+ <serviceId>urn:upnp-org:serviceId:WANIPv6FwCtrl1</serviceId>
+ <controlURL>/87895a19/upnp/control/WANIPv6FwCtrl1</controlURL>
+ <eventSubURL>/87895a19/upnp/control/WANIPv6FwCtrl1</eventSubURL>
+ <SCPDURL>/87895a19/wanipv6fwctrlSCPD.xml</SCPDURL>
+ </service>
+ </serviceList>
+ </device>
+ </deviceList>
+ </device>
+ </deviceList>
+ </device>
+</root> \ No newline at end of file
diff --git a/ext/miniupnpc/testigddescparse.c b/ext/miniupnpc/testigddescparse.c
new file mode 100644
index 00000000..c1907fd0
--- /dev/null
+++ b/ext/miniupnpc/testigddescparse.c
@@ -0,0 +1,187 @@
+/* $Id: testigddescparse.c,v 1.10 2015/08/06 09:55:24 nanard Exp $ */
+/* Project : miniupnp
+ * http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2008-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "igd_desc_parse.h"
+#include "minixml.h"
+#include "miniupnpc.h"
+
+/* count number of differences */
+int compare_service(struct IGDdatas_service * s, FILE * f)
+{
+ int n = 0;
+ char line[1024];
+
+ while(fgets(line, sizeof(line), f)) {
+ char * value;
+ char * equal;
+ char * name;
+ char * parsedvalue;
+ int l;
+ l = strlen(line);
+ while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n') || (line[l-1] == ' ')))
+ line[--l] = '\0';
+ if(l == 0)
+ break; /* end on blank line */
+ if(line[0] == '#')
+ continue; /* skip comments */
+ equal = strchr(line, '=');
+ if(equal == NULL) {
+ fprintf(stderr, "Warning, line does not contain '=' : %s\n", line);
+ continue;
+ }
+ *equal = '\0';
+ name = line;
+ while(*name == ' ' || *name == '\t')
+ name++;
+ l = strlen(name);
+ while((l > 0) && (name[l-1] == ' ' || name[l-1] == '\t'))
+ name[--l] = '\0';
+ value = equal + 1;
+ while(*value == ' ' || *value == '\t')
+ value++;
+ if(strcmp(name, "controlurl") == 0)
+ parsedvalue = s->controlurl;
+ else if(strcmp(name, "eventsuburl") == 0)
+ parsedvalue = s->eventsuburl;
+ else if(strcmp(name, "scpdurl") == 0)
+ parsedvalue = s->scpdurl;
+ else if(strcmp(name, "servicetype") == 0)
+ parsedvalue = s->servicetype;
+ else {
+ fprintf(stderr, "unknown field '%s'\n", name);
+ continue;
+ }
+ if(0 != strcmp(parsedvalue, value)) {
+ fprintf(stderr, "difference : '%s' != '%s'\n", parsedvalue, value);
+ n++;
+ }
+ }
+ return n;
+}
+
+int compare_igd(struct IGDdatas * p, FILE * f)
+{
+ int n = 0;
+ char line[1024];
+ struct IGDdatas_service * s;
+
+ while(fgets(line, sizeof(line), f)) {
+ char * colon;
+ int l = (int)strlen(line);
+ while((l > 0) && (line[l-1] == '\r' || (line[l-1] == '\n')))
+ line[--l] = '\0';
+ if(l == 0 || line[0] == '#')
+ continue; /* skip blank lines and comments */
+ colon = strchr(line, ':');
+ if(colon == NULL) {
+ fprintf(stderr, "Warning, no ':' : %s\n", line);
+ continue;
+ }
+ s = NULL;
+ *colon = '\0';
+ if(strcmp(line, "CIF") == 0)
+ s = &p->CIF;
+ else if(strcmp(line, "first") == 0)
+ s = &p->first;
+ else if(strcmp(line, "second") == 0)
+ s = &p->second;
+ else if(strcmp(line, "IPv6FC") == 0)
+ s = &p->IPv6FC;
+ else {
+ s = NULL;
+ fprintf(stderr, "*** unknown service '%s' ***\n", line);
+ n++;
+ continue;
+ }
+ n += compare_service(s, f);
+ }
+ if(n > 0)
+ fprintf(stderr, "*** %d difference%s ***\n", n, (n > 1) ? "s" : "");
+ return n;
+}
+
+int test_igd_desc_parse(char * buffer, int len, FILE * f)
+{
+ int n;
+ struct IGDdatas igd;
+ struct xmlparser parser;
+ struct UPNPUrls urls;
+
+ memset(&igd, 0, sizeof(struct IGDdatas));
+ memset(&parser, 0, sizeof(struct xmlparser));
+ parser.xmlstart = buffer;
+ parser.xmlsize = len;
+ parser.data = &igd;
+ parser.starteltfunc = IGDstartelt;
+ parser.endeltfunc = IGDendelt;
+ parser.datafunc = IGDdata;
+ parsexml(&parser);
+#ifdef DEBUG
+ printIGD(&igd);
+#endif /* DEBUG */
+ GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0);
+ printf("ipcondescURL='%s'\n", urls.ipcondescURL);
+ printf("controlURL='%s'\n", urls.controlURL);
+ printf("controlURL_CIF='%s'\n", urls.controlURL_CIF);
+ n = f ? compare_igd(&igd, f) : 0;
+ FreeUPNPUrls(&urls);
+ return n;
+}
+
+int main(int argc, char * * argv)
+{
+ FILE * f;
+ char * buffer;
+ int len;
+ int r;
+ if(argc<2) {
+ fprintf(stderr, "Usage: %s file.xml [file.values]\n", argv[0]);
+ return 1;
+ }
+ f = fopen(argv[1], "r");
+ if(!f) {
+ fprintf(stderr, "Cannot open %s for reading.\n", argv[1]);
+ return 1;
+ }
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buffer = malloc(len);
+ if(!buffer) {
+ fprintf(stderr, "Memory allocation error.\n");
+ fclose(f);
+ return 1;
+ }
+ r = (int)fread(buffer, 1, len, f);
+ if(r != len) {
+ fprintf(stderr, "Failed to read file %s. %d out of %d bytes.\n",
+ argv[1], r, len);
+ fclose(f);
+ free(buffer);
+ return 1;
+ }
+ fclose(f);
+ f = NULL;
+ if(argc > 2) {
+ f = fopen(argv[2], "r");
+ if(!f) {
+ fprintf(stderr, "Cannot open %s for reading.\n", argv[2]);
+ free(buffer);
+ return 1;
+ }
+ }
+ r = test_igd_desc_parse(buffer, len, f);
+ free(buffer);
+ if(f)
+ fclose(f);
+ return r;
+}
+
diff --git a/ext/miniupnpc/testminiwget.c b/ext/miniupnpc/testminiwget.c
new file mode 100644
index 00000000..8ae90320
--- /dev/null
+++ b/ext/miniupnpc/testminiwget.c
@@ -0,0 +1,53 @@
+/* $Id: testminiwget.c,v 1.4 2012/06/23 22:35:59 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2012 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#include <stdio.h>
+#include <stdlib.h>
+#include "miniwget.h"
+
+/**
+ * This program uses the miniwget / miniwget_getaddr function
+ * from miniwget.c in order to retreive a web ressource using
+ * a GET HTTP method, and store it in a file.
+ */
+int main(int argc, char * * argv)
+{
+ void * data;
+ int size, writtensize;
+ FILE *f;
+ char addr[64];
+
+ if(argc < 3) {
+ fprintf(stderr, "Usage:\t%s url file\n", argv[0]);
+ fprintf(stderr, "Example:\t%s http://www.google.com/ out.html\n", argv[0]);
+ return 1;
+ }
+ data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr), 0);
+ if(!data) {
+ fprintf(stderr, "Error fetching %s\n", argv[1]);
+ return 1;
+ }
+ printf("local address : %s\n", addr);
+ printf("got %d bytes\n", size);
+ f = fopen(argv[2], "wb");
+ if(!f) {
+ fprintf(stderr, "Cannot open file %s for writing\n", argv[2]);
+ free(data);
+ return 1;
+ }
+ writtensize = fwrite(data, 1, size, f);
+ if(writtensize != size) {
+ fprintf(stderr, "Could only write %d bytes out of %d to %s\n",
+ writtensize, size, argv[2]);
+ } else {
+ printf("%d bytes written to %s\n", writtensize, argv[2]);
+ }
+ fclose(f);
+ free(data);
+ return 0;
+}
+
diff --git a/ext/miniupnpc/testminiwget.sh b/ext/miniupnpc/testminiwget.sh
new file mode 100755
index 00000000..690b4056
--- /dev/null
+++ b/ext/miniupnpc/testminiwget.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+# $Id: testminiwget.sh,v 1.13 2015/09/03 17:57:44 nanard Exp $
+# project miniupnp : http://miniupnp.free.fr/
+# (c) 2011-2015 Thomas Bernard
+#
+# test program for miniwget.c
+# is usually invoked by "make check"
+#
+# This test program :
+# 1 - launches a local HTTP server (minihttptestserver)
+# 2 - uses testminiwget to retreive data from this server
+# 3 - compares served and received data
+# 4 - kills the local HTTP server and exits
+#
+# The script was tested and works with ksh, bash
+# it should now also run with dash
+
+TMPD=`mktemp -d -t miniwgetXXXXXXXXXX`
+HTTPSERVEROUT="${TMPD}/httpserverout"
+EXPECTEDFILE="${TMPD}/expectedfile"
+DOWNLOADEDFILE="${TMPD}/downloadedfile"
+PORT=
+RET=0
+
+case "$HAVE_IPV6" in
+ n|no|0)
+ ADDR=localhost
+ SERVERARGS=""
+ ;;
+ *)
+ ADDR="[::1]"
+ SERVERARGS="-6"
+ ;;
+
+esac
+
+#make minihttptestserver
+#make testminiwget
+
+# launching the test HTTP server
+./minihttptestserver $SERVERARGS -e $EXPECTEDFILE > $HTTPSERVEROUT &
+SERVERPID=$!
+while [ -z "$PORT" ]; do
+ sleep 1
+ PORT=`cat $HTTPSERVEROUT | sed 's/Listening on port \([0-9]*\)/\1/' `
+done
+echo "Test HTTP server is listening on $PORT"
+
+URL1="http://$ADDR:$PORT/index.html"
+URL2="http://$ADDR:$PORT/chunked"
+URL3="http://$ADDR:$PORT/addcrap"
+
+echo "standard test ..."
+./testminiwget $URL1 "${DOWNLOADEDFILE}.1"
+if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.1" ; then
+ echo "ok"
+else
+ echo "standard test FAILED"
+ RET=1
+fi
+
+echo "chunked transfert encoding test ..."
+./testminiwget $URL2 "${DOWNLOADEDFILE}.2"
+if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.2" ; then
+ echo "ok"
+else
+ echo "chunked transfert encoding test FAILED"
+ RET=1
+fi
+
+echo "response too long test ..."
+./testminiwget $URL3 "${DOWNLOADEDFILE}.3"
+if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.3" ; then
+ echo "ok"
+else
+ echo "response too long test FAILED"
+ RET=1
+fi
+
+# kill the test HTTP server
+kill $SERVERPID
+wait $SERVERPID
+
+# remove temporary files (for success cases)
+if [ $RET -eq 0 ]; then
+ rm -f "${DOWNLOADEDFILE}.1"
+ rm -f "${DOWNLOADEDFILE}.2"
+ rm -f "${DOWNLOADEDFILE}.3"
+ rm -f $EXPECTEDFILE $HTTPSERVEROUT
+ rmdir ${TMPD}
+else
+ echo "at least one of the test FAILED"
+ echo "directory ${TMPD} is left intact"
+fi
+exit $RET
+
diff --git a/ext/miniupnpc/testminixml.c b/ext/miniupnpc/testminixml.c
new file mode 100644
index 00000000..57c4a85e
--- /dev/null
+++ b/ext/miniupnpc/testminixml.c
@@ -0,0 +1,89 @@
+/* $Id: testminixml.c,v 1.10 2014/11/17 17:19:13 nanard Exp $
+ * MiniUPnP project
+ * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author : Thomas Bernard.
+ * Copyright (c) 2005-2014 Thomas Bernard
+ *
+ * testminixml.c
+ * test program for the "minixml" functions.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "minixml.h"
+#include "igd_desc_parse.h"
+
+/* ---------------------------------------------------------------------- */
+void printeltname1(void * d, const char * name, int l)
+{
+ int i;
+ (void)d;
+ printf("element ");
+ for(i=0;i<l;i++)
+ putchar(name[i]);
+}
+void printeltname2(void * d, const char * name, int l)
+{
+ int i;
+ (void)d;
+ putchar('/');
+ for(i=0;i<l;i++)
+ putchar(name[i]);
+ putchar('\n');
+}
+void printdata(void *d, const char * data, int l)
+{
+ int i;
+ (void)d;
+ printf("data : ");
+ for(i=0;i<l;i++)
+ putchar(data[i]);
+ putchar('\n');
+}
+
+void burptest(const char * buffer, int bufsize)
+{
+ struct IGDdatas data;
+ struct xmlparser parser;
+ /*objet IGDdatas */
+ memset(&data, 0, sizeof(struct IGDdatas));
+ /* objet xmlparser */
+ parser.xmlstart = buffer;
+ parser.xmlsize = bufsize;
+ parser.data = &data;
+ /*parser.starteltfunc = printeltname1;
+ parser.endeltfunc = printeltname2;
+ parser.datafunc = printdata; */
+ parser.starteltfunc = IGDstartelt;
+ parser.endeltfunc = IGDendelt;
+ parser.datafunc = IGDdata;
+ parsexml(&parser);
+#ifdef DEBUG
+ printIGD(&data);
+#endif /* DEBUG */
+}
+
+/* ----- main ---- */
+#define XML_MAX_SIZE (8192)
+int main(int argc, char * * argv)
+{
+ FILE * f;
+ char buffer[XML_MAX_SIZE];
+ int bufsize;
+ if(argc<2)
+ {
+ printf("usage:\t%s file.xml\n", argv[0]);
+ return 1;
+ }
+ f = fopen(argv[1], "r");
+ if(!f)
+ {
+ printf("cannot open file %s\n", argv[1]);
+ return 1;
+ }
+ bufsize = (int)fread(buffer, 1, XML_MAX_SIZE, f);
+ fclose(f);
+ burptest(buffer, bufsize);
+ return 0;
+}
+
diff --git a/ext/miniupnpc/testportlistingparse.c b/ext/miniupnpc/testportlistingparse.c
new file mode 100644
index 00000000..bd9247dc
--- /dev/null
+++ b/ext/miniupnpc/testportlistingparse.c
@@ -0,0 +1,151 @@
+/* $Id: testportlistingparse.c,v 1.2 2014/11/01 10:37:32 nanard Exp $ */
+/* Project : miniupnp
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author : Thomas Bernard
+ * Copyright (c) 2014 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+
+#include <string.h>
+#include <stdio.h>
+#include "portlistingparse.h"
+
+struct port_mapping {
+ unsigned int leasetime;
+ unsigned short externalport;
+ unsigned short internalport;
+ const char * remotehost;
+ const char * client;
+ const char * proto;
+ const char * desc;
+ unsigned char enabled;
+};
+
+/* return the number of differences */
+int test(const char * portListingXml, int portListingXmlLen,
+ const struct port_mapping * ref, int count)
+{
+ int i;
+ int r = 0;
+ struct PortMappingParserData data;
+ struct PortMapping * pm;
+
+ memset(&data, 0, sizeof(data));
+ ParsePortListing(portListingXml, portListingXmlLen, &data);
+ for(i = 0, pm = data.l_head;
+ (pm != NULL) && (i < count);
+ i++, pm = pm->l_next) {
+ printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
+ i, pm->protocol, pm->externalPort, pm->internalClient,
+ pm->internalPort,
+ pm->description, pm->remoteHost,
+ (unsigned)pm->leaseTime);
+ if(0 != strcmp(pm->protocol, ref[i].proto)) {
+ printf("protocol : '%s' != '%s'\n", pm->protocol, ref[i].proto);
+ r++;
+ }
+ if(pm->externalPort != ref[i].externalport) {
+ printf("externalPort : %hu != %hu\n",
+ pm->externalPort, ref[i].externalport);
+ r++;
+ }
+ if(0 != strcmp(pm->internalClient, ref[i].client)) {
+ printf("client : '%s' != '%s'\n",
+ pm->internalClient, ref[i].client);
+ r++;
+ }
+ if(pm->internalPort != ref[i].internalport) {
+ printf("internalPort : %hu != %hu\n",
+ pm->internalPort, ref[i].internalport);
+ r++;
+ }
+ if(0 != strcmp(pm->description, ref[i].desc)) {
+ printf("description : '%s' != '%s'\n",
+ pm->description, ref[i].desc);
+ r++;
+ }
+ if(0 != strcmp(pm->remoteHost, ref[i].remotehost)) {
+ printf("remoteHost : '%s' != '%s'\n",
+ pm->remoteHost, ref[i].remotehost);
+ r++;
+ }
+ if((unsigned)pm->leaseTime != ref[i].leasetime) {
+ printf("leaseTime : %u != %u\n",
+ (unsigned)pm->leaseTime, ref[i].leasetime);
+ r++;
+ }
+ if(pm->enabled != ref[i].enabled) {
+ printf("enabled : %d != %d\n",
+ (int)pm->enabled, (int)ref[i].enabled);
+ r++;
+ }
+ }
+ if((i != count) || (pm != NULL)) {
+ printf("count mismatch : i=%d count=%d pm=%p\n", i, count, pm);
+ r++;
+ }
+ FreePortListing(&data);
+ return r;
+}
+
+const char test_document[] =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\"\n"
+"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n"
+"xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection "
+"http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">\n"
+" <p:PortMappingEntry>\n"
+" <p:NewRemoteHost></p:NewRemoteHost>\n"
+" <p:NewExternalPort>5002</p:NewExternalPort>\n"
+" <p:NewProtocol>UDP</p:NewProtocol>\n"
+" <p:NewInternalPort>4001</p:NewInternalPort>\n"
+" <p:NewInternalClient>192.168.1.123</p:NewInternalClient>\n"
+" <p:NewEnabled>1</p:NewEnabled>\n"
+" <p:NewDescription>xxx</p:NewDescription>\n"
+" <p:NewLeaseTime>0</p:NewLeaseTime>\n"
+" </p:PortMappingEntry>\n"
+" <p:PortMappingEntry>\n"
+" <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>\n"
+" <p:NewExternalPort>2345</p:NewExternalPort>\n"
+" <p:NewProtocol>TCP</p:NewProtocol>\n"
+" <p:NewInternalPort>2349</p:NewInternalPort>\n"
+" <p:NewInternalClient>192.168.1.137</p:NewInternalClient>\n"
+" <p:NewEnabled>1</p:NewEnabled>\n"
+" <p:NewDescription>dooom</p:NewDescription>\n"
+" <p:NewLeaseTime>346</p:NewLeaseTime>\n"
+" </p:PortMappingEntry>\n"
+" <p:PortMappingEntry>\n"
+" <p:NewRemoteHost>134.231.2.11</p:NewRemoteHost>\n"
+" <p:NewExternalPort>12345</p:NewExternalPort>\n"
+" <p:NewProtocol>TCP</p:NewProtocol>\n"
+" <p:NewInternalPort>12345</p:NewInternalPort>\n"
+" <p:NewInternalClient>192.168.1.137</p:NewInternalClient>\n"
+" <p:NewEnabled>1</p:NewEnabled>\n"
+" <p:NewDescription>dooom A</p:NewDescription>\n"
+" <p:NewLeaseTime>347</p:NewLeaseTime>\n"
+" </p:PortMappingEntry>\n"
+"</p:PortMappingList>";
+
+#define PORT_MAPPINGS_COUNT 3
+const struct port_mapping port_mappings[PORT_MAPPINGS_COUNT] = {
+{347, 12345, 12345, "134.231.2.11", "192.168.1.137", "TCP", "dooom A", 1},
+{346, 2345, 2349, "202.233.2.1", "192.168.1.137", "TCP", "dooom", 1},
+{0, 5002, 4001, "", "192.168.1.123", "UDP", "xxx", 1}
+};
+
+/* --- main --- */
+int main(void)
+{
+ int r;
+ r = test(test_document, sizeof(test_document) - 1,
+ port_mappings, PORT_MAPPINGS_COUNT);
+ if(r == 0) {
+ printf("test of portlistingparse OK\n");
+ return 0;
+ } else {
+ printf("test FAILED (%d differences counted)\n", r);
+ return 1;
+ }
+}
+
diff --git a/ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue b/ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue
new file mode 100644
index 00000000..48ca0ccc
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue
@@ -0,0 +1,3 @@
+NewRemoteHost=
+NewExternalPort=123
+NewProtocol=TCP
diff --git a/ext/miniupnpc/testreplyparse/DeletePortMapping.xml b/ext/miniupnpc/testreplyparse/DeletePortMapping.xml
new file mode 100644
index 00000000..a955c53f
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/DeletePortMapping.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:DeletePortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewRemoteHost></NewRemoteHost><NewExternalPort>123</NewExternalPort>
+<NewProtocol>TCP</NewProtocol></u:DeletePortMapping></s:Body>
+
+</s:Envelope>
+
diff --git a/ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue b/ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue
new file mode 100644
index 00000000..5aa75f88
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue
@@ -0,0 +1,2 @@
+NewExternalIPAddress=1.2.3.4
+
diff --git a/ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml b/ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml
new file mode 100644
index 00000000..db7ec1f9
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetExternalIPAddressResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewExternalIPAddress>1.2.3.4</NewExternalIPAddress></u:GetExternalIPAddressResponse></s:Body></s:Envelope>
+
diff --git a/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue b/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue
new file mode 100644
index 00000000..26b169c3
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue
@@ -0,0 +1,3 @@
+NewProtocol=UDP
+NewExternalPort=12345
+NewRemoteHost=
diff --git a/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml b/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml
new file mode 100644
index 00000000..bbb540ea
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetSpecificPortMappingEntry xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewRemoteHost></NewRemoteHost><NewExternalPort>12345</NewExternalPort><NewProtocol>UDP</NewProtocol></u:GetSpecificPortMappingEntry></s:Body></s:Envelope>
+
diff --git a/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue b/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue
new file mode 100644
index 00000000..2189789b
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue
@@ -0,0 +1,5 @@
+NewInternalPort=12345
+NewInternalClient=192.168.10.110
+NewEnabled=1
+NewPortMappingDescription=libminiupnpc
+NewLeaseDuration=0
diff --git a/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml b/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml
new file mode 100644
index 00000000..77e8d9c7
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetSpecificPortMappingEntryResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewInternalPort>12345</NewInternalPort><NewInternalClient>192.168.10.110</NewInternalClient><NewEnabled>1</NewEnabled><NewPortMappingDescription>libminiupnpc</NewPortMappingDescription><NewLeaseDuration>0</NewLeaseDuration></u:GetSpecificPortMappingEntryResponse></s:Body></s:Envelope>
+
diff --git a/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue b/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue
new file mode 100644
index 00000000..f78c7e2a
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue
@@ -0,0 +1 @@
+NewDefaultConnectionService=uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID
diff --git a/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml b/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml
new file mode 100644
index 00000000..ac04c07a
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><u:SetDefaultConnectionService xmlns:u="urn:schemas-upnp-org:service:Layer3Forwarding:1"><NewDefaultConnectionService>uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID</NewDefaultConnectionService></u:SetDefaultConnectionService></s:Body></s:Envelope>
diff --git a/ext/miniupnpc/testreplyparse/readme.txt b/ext/miniupnpc/testreplyparse/readme.txt
new file mode 100644
index 00000000..3eb1f015
--- /dev/null
+++ b/ext/miniupnpc/testreplyparse/readme.txt
@@ -0,0 +1,7 @@
+This directory contains files used for validation of upnpreplyparse.c code.
+
+Each .xml file to parse should give the results which are in the .namevalue
+file.
+
+A .namevalue file contain name=value lines.
+
diff --git a/ext/miniupnpc/testupnpigd.py b/ext/miniupnpc/testupnpigd.py
new file mode 100755
index 00000000..6d167a4c
--- /dev/null
+++ b/ext/miniupnpc/testupnpigd.py
@@ -0,0 +1,84 @@
+#! /usr/bin/python
+# $Id: testupnpigd.py,v 1.4 2008/10/11 10:27:20 nanard Exp $
+# MiniUPnP project
+# Author : Thomas Bernard
+# This Sample code is public domain.
+# website : http://miniupnp.tuxfamily.org/
+
+# import the python miniupnpc module
+import miniupnpc
+import socket
+import BaseHTTPServer
+
+# function definition
+def list_redirections():
+ i = 0
+ while True:
+ p = u.getgenericportmapping(i)
+ if p==None:
+ break
+ print i, p
+ i = i + 1
+
+#define the handler class for HTTP connections
+class handler_class(BaseHTTPServer.BaseHTTPRequestHandler):
+ def do_GET(self):
+ self.send_response(200)
+ self.end_headers()
+ self.wfile.write("OK MON GARS")
+
+# create the object
+u = miniupnpc.UPnP()
+#print 'inital(default) values :'
+#print ' discoverdelay', u.discoverdelay
+#print ' lanaddr', u.lanaddr
+#print ' multicastif', u.multicastif
+#print ' minissdpdsocket', u.minissdpdsocket
+u.discoverdelay = 200;
+
+try:
+ print 'Discovering... delay=%ums' % u.discoverdelay
+ ndevices = u.discover()
+ print ndevices, 'device(s) detected'
+
+ # select an igd
+ u.selectigd()
+ # display information about the IGD and the internet connection
+ print 'local ip address :', u.lanaddr
+ externalipaddress = u.externalipaddress()
+ print 'external ip address :', externalipaddress
+ print u.statusinfo(), u.connectiontype()
+
+ #instanciate a HTTPd object. The port is assigned by the system.
+ httpd = BaseHTTPServer.HTTPServer((u.lanaddr, 0), handler_class)
+ eport = httpd.server_port
+
+ # find a free port for the redirection
+ r = u.getspecificportmapping(eport, 'TCP')
+ while r != None and eport < 65536:
+ eport = eport + 1
+ r = u.getspecificportmapping(eport, 'TCP')
+
+ print 'trying to redirect %s port %u TCP => %s port %u TCP' % (externalipaddress, eport, u.lanaddr, httpd.server_port)
+
+ b = u.addportmapping(eport, 'TCP', u.lanaddr, httpd.server_port,
+ 'UPnP IGD Tester port %u' % eport, '')
+ if b:
+ print 'Success. Now waiting for some HTTP request on http://%s:%u' % (externalipaddress ,eport)
+ try:
+ httpd.handle_request()
+ httpd.server_close()
+ except KeyboardInterrupt, details:
+ print "CTRL-C exception!", details
+ b = u.deleteportmapping(eport, 'TCP')
+ if b:
+ print 'Successfully deleted port mapping'
+ else:
+ print 'Failed to remove port mapping'
+ else:
+ print 'Failed'
+
+ httpd.server_close()
+
+except Exception, e:
+ print 'Exception :', e
diff --git a/ext/miniupnpc/testupnpreplyparse.c b/ext/miniupnpc/testupnpreplyparse.c
new file mode 100644
index 00000000..7ba7131e
--- /dev/null
+++ b/ext/miniupnpc/testupnpreplyparse.c
@@ -0,0 +1,96 @@
+/* $Id: testupnpreplyparse.c,v 1.4 2014/01/27 11:45:19 nanard Exp $ */
+/* MiniUPnP project
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * (c) 2006-2014 Thomas Bernard
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "upnpreplyparse.h"
+
+int
+test_parsing(const char * buf, int len, FILE * f)
+{
+ char line[1024];
+ struct NameValueParserData pdata;
+ int ok = 1;
+ ParseNameValue(buf, len, &pdata);
+ /* check result */
+ if(f != NULL)
+ {
+ while(fgets(line, sizeof(line), f))
+ {
+ char * value;
+ char * equal;
+ char * parsedvalue;
+ int l;
+ l = strlen(line);
+ while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n')))
+ line[--l] = '\0';
+ /* skip empty lines */
+ if(l == 0)
+ continue;
+ equal = strchr(line, '=');
+ if(equal == NULL)
+ {
+ fprintf(stderr, "Warning, line does not contain '=' : %s\n", line);
+ continue;
+ }
+ *equal = '\0';
+ value = equal + 1;
+ parsedvalue = GetValueFromNameValueList(&pdata, line);
+ if((parsedvalue == NULL) || (strcmp(parsedvalue, value) != 0))
+ {
+ fprintf(stderr, "Element <%s> : expecting value '%s', got '%s'\n",
+ line, value, parsedvalue ? parsedvalue : "<null string>");
+ ok = 0;
+ }
+ }
+ }
+ ClearNameValueList(&pdata);
+ return ok;
+}
+
+int main(int argc, char * * argv)
+{
+ FILE * f;
+ char buffer[4096];
+ int l;
+ int ok;
+
+ if(argc<2)
+ {
+ fprintf(stderr, "Usage: %s file.xml [file.namevalues]\n", argv[0]);
+ return 1;
+ }
+ f = fopen(argv[1], "r");
+ if(!f)
+ {
+ fprintf(stderr, "Error : can not open file %s\n", argv[1]);
+ return 2;
+ }
+ l = fread(buffer, 1, sizeof(buffer)-1, f);
+ fclose(f);
+ f = NULL;
+ buffer[l] = '\0';
+ if(argc > 2)
+ {
+ f = fopen(argv[2], "r");
+ if(!f)
+ {
+ fprintf(stderr, "Error : can not open file %s\n", argv[2]);
+ return 2;
+ }
+ }
+#ifdef DEBUG
+ DisplayNameValueList(buffer, l);
+#endif
+ ok = test_parsing(buffer, l, f);
+ if(f)
+ {
+ fclose(f);
+ }
+ return ok ? 0 : 3;
+}
+
diff --git a/ext/miniupnpc/testupnpreplyparse.sh b/ext/miniupnpc/testupnpreplyparse.sh
new file mode 100755
index 00000000..992930b7
--- /dev/null
+++ b/ext/miniupnpc/testupnpreplyparse.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+for f in testreplyparse/*.xml ; do
+ bf="`dirname $f`/`basename $f .xml`"
+ if ./testupnpreplyparse $f $bf.namevalue ; then
+ echo "$f : passed"
+ else
+ echo "$f : FAILED"
+ exit 1
+ fi
+done
+
+exit 0
+
diff --git a/ext/miniupnpc/updateminiupnpcstrings.sh b/ext/miniupnpc/updateminiupnpcstrings.sh
new file mode 100755
index 00000000..dde4354a
--- /dev/null
+++ b/ext/miniupnpc/updateminiupnpcstrings.sh
@@ -0,0 +1,53 @@
+#! /bin/sh
+# $Id: updateminiupnpcstrings.sh,v 1.7 2011/01/04 11:41:53 nanard Exp $
+# project miniupnp : http://miniupnp.free.fr/
+# (c) 2009 Thomas Bernard
+
+FILE=miniupnpcstrings.h
+TMPFILE=miniupnpcstrings.h.tmp
+TEMPLATE_FILE=${FILE}.in
+
+# detecting the OS name and version
+OS_NAME=`uname -s`
+OS_VERSION=`uname -r`
+if [ -f /etc/debian_version ]; then
+ OS_NAME=Debian
+ OS_VERSION=`cat /etc/debian_version`
+fi
+# use lsb_release (Linux Standard Base) when available
+LSB_RELEASE=`which lsb_release`
+if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then
+ OS_NAME=`${LSB_RELEASE} -i -s`
+ OS_VERSION=`${LSB_RELEASE} -r -s`
+ case $OS_NAME in
+ Debian)
+ #OS_VERSION=`${LSB_RELEASE} -c -s`
+ ;;
+ Ubuntu)
+ #OS_VERSION=`${LSB_RELEASE} -c -s`
+ ;;
+ esac
+fi
+
+# on AmigaOS 3, uname -r returns "unknown", so we use uname -v
+if [ "$OS_NAME" = "AmigaOS" ]; then
+ if [ "$OS_VERSION" = "unknown" ]; then
+ OS_VERSION=`uname -v`
+ fi
+fi
+
+echo "Detected OS [$OS_NAME] version [$OS_VERSION]"
+MINIUPNPC_VERSION=`cat VERSION`
+echo "MiniUPnPc version [${MINIUPNPC_VERSION}]"
+
+EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|"
+#echo $EXPR
+test -f ${FILE}.in
+echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE."
+sed -e "$EXPR" < $TEMPLATE_FILE > $TMPFILE
+
+EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|"
+echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE."
+sed -e "$EXPR" < $TMPFILE > $FILE
+rm $TMPFILE
+
diff --git a/ext/miniupnpc/upnpc.c b/ext/miniupnpc/upnpc.c
new file mode 100644
index 00000000..8bc552ef
--- /dev/null
+++ b/ext/miniupnpc/upnpc.c
@@ -0,0 +1,833 @@
+/* $Id: upnpc.c,v 1.112 2015/10/08 16:15:48 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#define snprintf _snprintf
+#else
+/* for IPPROTO_TCP / IPPROTO_UDP */
+#include <netinet/in.h>
+#endif
+#include <ctype.h>
+#include "miniwget.h"
+#include "miniupnpc.h"
+#include "upnpcommands.h"
+#include "upnperrors.h"
+#include "miniupnpcstrings.h"
+
+/* protofix() checks if protocol is "UDP" or "TCP"
+ * returns NULL if not */
+const char * protofix(const char * proto)
+{
+ static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
+ static const char proto_udp[4] = { 'U', 'D', 'P', 0};
+ int i, b;
+ for(i=0, b=1; i<4; i++)
+ b = b && ( (proto[i] == proto_tcp[i])
+ || (proto[i] == (proto_tcp[i] | 32)) );
+ if(b)
+ return proto_tcp;
+ for(i=0, b=1; i<4; i++)
+ b = b && ( (proto[i] == proto_udp[i])
+ || (proto[i] == (proto_udp[i] | 32)) );
+ if(b)
+ return proto_udp;
+ return 0;
+}
+
+/* is_int() checks if parameter is an integer or not
+ * 1 for integer
+ * 0 for not an integer */
+int is_int(char const* s)
+{
+ if(s == NULL)
+ return 0;
+ while(*s) {
+ /* #define isdigit(c) ((c) >= '0' && (c) <= '9') */
+ if(!isdigit(*s))
+ return 0;
+ s++;
+ }
+ return 1;
+}
+
+static void DisplayInfos(struct UPNPUrls * urls,
+ struct IGDdatas * data)
+{
+ char externalIPAddress[40];
+ char connectionType[64];
+ char status[64];
+ char lastconnerr[64];
+ unsigned int uptime;
+ unsigned int brUp, brDown;
+ time_t timenow, timestarted;
+ int r;
+ if(UPNP_GetConnectionTypeInfo(urls->controlURL,
+ data->first.servicetype,
+ connectionType) != UPNPCOMMAND_SUCCESS)
+ printf("GetConnectionTypeInfo failed.\n");
+ else
+ printf("Connection Type : %s\n", connectionType);
+ if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
+ status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS)
+ printf("GetStatusInfo failed.\n");
+ else
+ printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
+ status, uptime, lastconnerr);
+ timenow = time(NULL);
+ timestarted = timenow - uptime;
+ printf(" Time started : %s", ctime(&timestarted));
+ if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
+ &brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
+ printf("GetLinkLayerMaxBitRates failed.\n");
+ } else {
+ printf("MaxBitRateDown : %u bps", brDown);
+ if(brDown >= 1000000) {
+ printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10);
+ } else if(brDown >= 1000) {
+ printf(" (%u Kbps)", brDown / 1000);
+ }
+ printf(" MaxBitRateUp %u bps", brUp);
+ if(brUp >= 1000000) {
+ printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10);
+ } else if(brUp >= 1000) {
+ printf(" (%u Kbps)", brUp / 1000);
+ }
+ printf("\n");
+ }
+ r = UPNP_GetExternalIPAddress(urls->controlURL,
+ data->first.servicetype,
+ externalIPAddress);
+ if(r != UPNPCOMMAND_SUCCESS) {
+ printf("GetExternalIPAddress failed. (errorcode=%d)\n", r);
+ } else {
+ printf("ExternalIPAddress = %s\n", externalIPAddress);
+ }
+}
+
+static void GetConnectionStatus(struct UPNPUrls * urls,
+ struct IGDdatas * data)
+{
+ unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
+ DisplayInfos(urls, data);
+ bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
+ bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
+ packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
+ packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
+ printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
+ printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
+}
+
+static void ListRedirections(struct UPNPUrls * urls,
+ struct IGDdatas * data)
+{
+ int r;
+ int i = 0;
+ char index[6];
+ char intClient[40];
+ char intPort[6];
+ char extPort[6];
+ char protocol[4];
+ char desc[80];
+ char enabled[6];
+ char rHost[64];
+ char duration[16];
+ /*unsigned int num=0;
+ UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
+ printf("PortMappingNumberOfEntries : %u\n", num);*/
+ printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
+ do {
+ snprintf(index, 6, "%d", i);
+ rHost[0] = '\0'; enabled[0] = '\0';
+ duration[0] = '\0'; desc[0] = '\0';
+ extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
+ r = UPNP_GetGenericPortMappingEntry(urls->controlURL,
+ data->first.servicetype,
+ index,
+ extPort, intClient, intPort,
+ protocol, desc, enabled,
+ rHost, duration);
+ if(r==0)
+ /*
+ printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
+ " desc='%s' rHost='%s'\n",
+ i, protocol, extPort, intClient, intPort,
+ enabled, duration,
+ desc, rHost);
+ */
+ printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n",
+ i, protocol, extPort, intClient, intPort,
+ desc, rHost, duration);
+ else
+ printf("GetGenericPortMappingEntry() returned %d (%s)\n",
+ r, strupnperror(r));
+ i++;
+ } while(r==0);
+}
+
+static void NewListRedirections(struct UPNPUrls * urls,
+ struct IGDdatas * data)
+{
+ int r;
+ int i = 0;
+ struct PortMappingParserData pdata;
+ struct PortMapping * pm;
+
+ memset(&pdata, 0, sizeof(struct PortMappingParserData));
+ r = UPNP_GetListOfPortMappings(urls->controlURL,
+ data->first.servicetype,
+ "0",
+ "65535",
+ "TCP",
+ "1000",
+ &pdata);
+ if(r == UPNPCOMMAND_SUCCESS)
+ {
+ printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
+ for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
+ {
+ printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
+ i, pm->protocol, pm->externalPort, pm->internalClient,
+ pm->internalPort,
+ pm->description, pm->remoteHost,
+ (unsigned)pm->leaseTime);
+ i++;
+ }
+ FreePortListing(&pdata);
+ }
+ else
+ {
+ printf("GetListOfPortMappings() returned %d (%s)\n",
+ r, strupnperror(r));
+ }
+ r = UPNP_GetListOfPortMappings(urls->controlURL,
+ data->first.servicetype,
+ "0",
+ "65535",
+ "UDP",
+ "1000",
+ &pdata);
+ if(r == UPNPCOMMAND_SUCCESS)
+ {
+ for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
+ {
+ printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
+ i, pm->protocol, pm->externalPort, pm->internalClient,
+ pm->internalPort,
+ pm->description, pm->remoteHost,
+ (unsigned)pm->leaseTime);
+ i++;
+ }
+ FreePortListing(&pdata);
+ }
+ else
+ {
+ printf("GetListOfPortMappings() returned %d (%s)\n",
+ r, strupnperror(r));
+ }
+}
+
+/* Test function
+ * 1 - get connection type
+ * 2 - get extenal ip address
+ * 3 - Add port mapping
+ * 4 - get this port mapping from the IGD */
+static void SetRedirectAndTest(struct UPNPUrls * urls,
+ struct IGDdatas * data,
+ const char * iaddr,
+ const char * iport,
+ const char * eport,
+ const char * proto,
+ const char * leaseDuration,
+ const char * description,
+ int addAny)
+{
+ char externalIPAddress[40];
+ char intClient[40];
+ char intPort[6];
+ char reservedPort[6];
+ char duration[16];
+ int r;
+
+ if(!iaddr || !iport || !eport || !proto)
+ {
+ fprintf(stderr, "Wrong arguments\n");
+ return;
+ }
+ proto = protofix(proto);
+ if(!proto)
+ {
+ fprintf(stderr, "invalid protocol\n");
+ return;
+ }
+
+ r = UPNP_GetExternalIPAddress(urls->controlURL,
+ data->first.servicetype,
+ externalIPAddress);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("GetExternalIPAddress failed.\n");
+ else
+ printf("ExternalIPAddress = %s\n", externalIPAddress);
+
+ if (addAny) {
+ r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype,
+ eport, iport, iaddr, description,
+ proto, 0, leaseDuration, reservedPort);
+ if(r==UPNPCOMMAND_SUCCESS)
+ eport = reservedPort;
+ else
+ printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n",
+ eport, iport, iaddr, r, strupnperror(r));
+ } else {
+ r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
+ eport, iport, iaddr, description,
+ proto, 0, leaseDuration);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
+ eport, iport, iaddr, r, strupnperror(r));
+ }
+
+ r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
+ data->first.servicetype,
+ eport, proto, NULL/*remoteHost*/,
+ intClient, intPort, NULL/*desc*/,
+ NULL/*enabled*/, duration);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
+ r, strupnperror(r));
+ else {
+ printf("InternalIP:Port = %s:%s\n", intClient, intPort);
+ printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
+ externalIPAddress, eport, proto, intClient, intPort, duration);
+ }
+}
+
+static void
+RemoveRedirect(struct UPNPUrls * urls,
+ struct IGDdatas * data,
+ const char * eport,
+ const char * proto,
+ const char * remoteHost)
+{
+ int r;
+ if(!proto || !eport)
+ {
+ fprintf(stderr, "invalid arguments\n");
+ return;
+ }
+ proto = protofix(proto);
+ if(!proto)
+ {
+ fprintf(stderr, "protocol invalid\n");
+ return;
+ }
+ r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
+ printf("UPNP_DeletePortMapping() returned : %d\n", r);
+}
+
+static void
+RemoveRedirectRange(struct UPNPUrls * urls,
+ struct IGDdatas * data,
+ const char * ePortStart, char const * ePortEnd,
+ const char * proto, const char * manage)
+{
+ int r;
+
+ if (!manage)
+ manage = "0";
+
+ if(!proto || !ePortStart || !ePortEnd)
+ {
+ fprintf(stderr, "invalid arguments\n");
+ return;
+ }
+ proto = protofix(proto);
+ if(!proto)
+ {
+ fprintf(stderr, "protocol invalid\n");
+ return;
+ }
+ r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
+ printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
+}
+
+/* IGD:2, functions for service WANIPv6FirewallControl:1 */
+static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
+{
+ unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
+ int firewallEnabled = 0, inboundPinholeAllowed = 0;
+
+ UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed);
+ printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed);
+ printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No");
+
+ bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
+ bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
+ packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
+ packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
+ printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
+ printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
+}
+
+/* Test function
+ * 1 - Add pinhole
+ * 2 - Check if pinhole is working from the IGD side */
+static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data,
+ const char * remoteaddr, const char * eport,
+ const char * intaddr, const char * iport,
+ const char * proto, const char * lease_time)
+{
+ char uniqueID[8];
+ /*int isWorking = 0;*/
+ int r;
+ char proto_tmp[8];
+
+ if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
+ {
+ fprintf(stderr, "Wrong arguments\n");
+ return;
+ }
+ if(atoi(proto) == 0)
+ {
+ const char * protocol;
+ protocol = protofix(proto);
+ if(protocol && (strcmp("TCP", protocol) == 0))
+ {
+ snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
+ proto = proto_tmp;
+ }
+ else if(protocol && (strcmp("UDP", protocol) == 0))
+ {
+ snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
+ proto = proto_tmp;
+ }
+ else
+ {
+ fprintf(stderr, "invalid protocol\n");
+ return;
+ }
+ }
+ r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
+ remoteaddr, eport, intaddr, iport, r, strupnperror(r));
+ else
+ {
+ printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
+ remoteaddr, eport, intaddr, iport, uniqueID);
+ /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
+ printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/
+ }
+}
+
+/* Test function
+ * 1 - Check if pinhole is working from the IGD side
+ * 2 - Update pinhole */
+static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data,
+ const char * uniqueID, const char * lease_time)
+{
+ int isWorking = 0;
+ int r;
+
+ if(!uniqueID || !lease_time)
+ {
+ fprintf(stderr, "Wrong arguments\n");
+ return;
+ }
+ r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
+ printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
+ if(isWorking || r==709)
+ {
+ r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time);
+ printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
+ }
+}
+
+/* Test function
+ * Get pinhole timeout
+ */
+static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data,
+ const char * remoteaddr, const char * eport,
+ const char * intaddr, const char * iport,
+ const char * proto)
+{
+ int timeout = 0;
+ int r;
+
+ if(!intaddr || !remoteaddr || !iport || !eport || !proto)
+ {
+ fprintf(stderr, "Wrong arguments\n");
+ return;
+ }
+
+ r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
+ intaddr, iport, remoteaddr, eport, r, strupnperror(r));
+ else
+ printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout);
+}
+
+static void
+GetPinholePackets(struct UPNPUrls * urls,
+ struct IGDdatas * data, const char * uniqueID)
+{
+ int r, pinholePackets = 0;
+ if(!uniqueID)
+ {
+ fprintf(stderr, "invalid arguments\n");
+ return;
+ }
+ r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r));
+ else
+ printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets);
+}
+
+static void
+CheckPinhole(struct UPNPUrls * urls,
+ struct IGDdatas * data, const char * uniqueID)
+{
+ int r, isWorking = 0;
+ if(!uniqueID)
+ {
+ fprintf(stderr, "invalid arguments\n");
+ return;
+ }
+ r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
+ else
+ printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
+}
+
+static void
+RemovePinhole(struct UPNPUrls * urls,
+ struct IGDdatas * data, const char * uniqueID)
+{
+ int r;
+ if(!uniqueID)
+ {
+ fprintf(stderr, "invalid arguments\n");
+ return;
+ }
+ r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID);
+ printf("UPNP_DeletePinhole() returned : %d\n", r);
+}
+
+
+/* sample upnp client program */
+int main(int argc, char ** argv)
+{
+ char command = 0;
+ char ** commandargv = 0;
+ int commandargc = 0;
+ struct UPNPDev * devlist = 0;
+ char lanaddr[64]; /* my ip address on the LAN */
+ int i;
+ const char * rootdescurl = 0;
+ const char * multicastif = 0;
+ const char * minissdpdpath = 0;
+ int localport = UPNP_LOCAL_PORT_ANY;
+ int retcode = 0;
+ int error = 0;
+ int ipv6 = 0;
+ unsigned char ttl = 2; /* defaulting to 2 */
+ const char * description = 0;
+
+#ifdef _WIN32
+ WSADATA wsaData;
+ int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
+ if(nResult != NO_ERROR)
+ {
+ fprintf(stderr, "WSAStartup() failed.\n");
+ return -1;
+ }
+#endif
+ printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
+ printf(" (c) 2005-2015 Thomas Bernard.\n");
+ printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
+ "for more information.\n");
+ /* command line processing */
+ for(i=1; i<argc; i++)
+ {
+ if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h"))
+ {
+ command = 0;
+ break;
+ }
+ if(argv[i][0] == '-')
+ {
+ if(argv[i][1] == 'u')
+ rootdescurl = argv[++i];
+ else if(argv[i][1] == 'm')
+ multicastif = argv[++i];
+ else if(argv[i][1] == 'z')
+ {
+ char junk;
+ if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
+ localport<0 || localport>65535 ||
+ (localport >1 && localport < 1024))
+ {
+ fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
+ localport = UPNP_LOCAL_PORT_ANY;
+ break;
+ }
+ }
+ else if(argv[i][1] == 'p')
+ minissdpdpath = argv[++i];
+ else if(argv[i][1] == '6')
+ ipv6 = 1;
+ else if(argv[i][1] == 'e')
+ description = argv[++i];
+ else if(argv[i][1] == 't')
+ ttl = (unsigned char)atoi(argv[++i]);
+ else
+ {
+ command = argv[i][1];
+ i++;
+ commandargv = argv + i;
+ commandargc = argc - i;
+ break;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "option '%s' invalid\n", argv[i]);
+ }
+ }
+
+ if(!command
+ || (command == 'a' && commandargc<4)
+ || (command == 'd' && argc<2)
+ || (command == 'r' && argc<2)
+ || (command == 'A' && commandargc<6)
+ || (command == 'U' && commandargc<2)
+ || (command == 'D' && commandargc<1))
+ {
+ fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -d external_port protocol <remote host>\n\t\tDelete port redirection\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]);
+ fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]);
+ fprintf(stderr, "\nprotocol is UDP or TCP\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -e description : set description for port mapping.\n");
+ fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
+ fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
+ fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
+ fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
+ fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
+ fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n");
+ return 1;
+ }
+
+ if( rootdescurl
+ || (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
+ localport, ipv6, ttl, &error)))
+ {
+ struct UPNPDev * device;
+ struct UPNPUrls urls;
+ struct IGDdatas data;
+ if(devlist)
+ {
+ printf("List of UPNP devices found on the network :\n");
+ for(device = devlist; device; device = device->pNext)
+ {
+ printf(" desc: %s\n st: %s\n\n",
+ device->descURL, device->st);
+ }
+ }
+ else if(!rootdescurl)
+ {
+ printf("upnpDiscover() error code=%d\n", error);
+ }
+ i = 1;
+ if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr)))
+ || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))))
+ {
+ switch(i) {
+ case 1:
+ printf("Found valid IGD : %s\n", urls.controlURL);
+ break;
+ case 2:
+ printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
+ printf("Trying to continue anyway\n");
+ break;
+ case 3:
+ printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
+ printf("Trying to continue anyway\n");
+ break;
+ default:
+ printf("Found device (igd ?) : %s\n", urls.controlURL);
+ printf("Trying to continue anyway\n");
+ }
+ printf("Local LAN ip address : %s\n", lanaddr);
+ #if 0
+ printf("getting \"%s\"\n", urls.ipcondescURL);
+ descXML = miniwget(urls.ipcondescURL, &descXMLsize);
+ if(descXML)
+ {
+ /*fwrite(descXML, 1, descXMLsize, stdout);*/
+ free(descXML); descXML = NULL;
+ }
+ #endif
+
+ switch(command)
+ {
+ case 'l':
+ DisplayInfos(&urls, &data);
+ ListRedirections(&urls, &data);
+ break;
+ case 'L':
+ NewListRedirections(&urls, &data);
+ break;
+ case 'a':
+ SetRedirectAndTest(&urls, &data,
+ commandargv[0], commandargv[1],
+ commandargv[2], commandargv[3],
+ (commandargc > 4)?commandargv[4]:"0",
+ description, 0);
+ break;
+ case 'd':
+ RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
+ commandargc > 2 ? commandargv[2] : NULL);
+ break;
+ case 'n': /* aNy */
+ SetRedirectAndTest(&urls, &data,
+ commandargv[0], commandargv[1],
+ commandargv[2], commandargv[3],
+ (commandargc > 4)?commandargv[4]:"0",
+ description, 1);
+ break;
+ case 'N':
+ if (commandargc < 3)
+ fprintf(stderr, "too few arguments\n");
+
+ RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
+ commandargc > 3 ? commandargv[3] : NULL);
+ break;
+ case 's':
+ GetConnectionStatus(&urls, &data);
+ break;
+ case 'r':
+ i = 0;
+ while(i<commandargc)
+ {
+ if(!is_int(commandargv[i])) {
+ /* 1st parameter not an integer : error */
+ fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]);
+ retcode = 1;
+ break;
+ } else if(is_int(commandargv[i+1])){
+ /* 2nd parameter is an integer : <port> <external_port> <protocol> */
+ SetRedirectAndTest(&urls, &data,
+ lanaddr, commandargv[i],
+ commandargv[i+1], commandargv[i+2], "0",
+ description, 0);
+ i+=3; /* 3 parameters parsed */
+ } else {
+ /* 2nd parameter not an integer : <port> <protocol> */
+ SetRedirectAndTest(&urls, &data,
+ lanaddr, commandargv[i],
+ commandargv[i], commandargv[i+1], "0",
+ description, 0);
+ i+=2; /* 2 parameters parsed */
+ }
+ }
+ break;
+ case 'A':
+ SetPinholeAndTest(&urls, &data,
+ commandargv[0], commandargv[1],
+ commandargv[2], commandargv[3],
+ commandargv[4], commandargv[5]);
+ break;
+ case 'U':
+ GetPinholeAndUpdate(&urls, &data,
+ commandargv[0], commandargv[1]);
+ break;
+ case 'C':
+ for(i=0; i<commandargc; i++)
+ {
+ CheckPinhole(&urls, &data, commandargv[i]);
+ }
+ break;
+ case 'K':
+ for(i=0; i<commandargc; i++)
+ {
+ GetPinholePackets(&urls, &data, commandargv[i]);
+ }
+ break;
+ case 'D':
+ for(i=0; i<commandargc; i++)
+ {
+ RemovePinhole(&urls, &data, commandargv[i]);
+ }
+ break;
+ case 'S':
+ GetFirewallStatus(&urls, &data);
+ break;
+ case 'G':
+ GetPinholeOutboundTimeout(&urls, &data,
+ commandargv[0], commandargv[1],
+ commandargv[2], commandargv[3],
+ commandargv[4]);
+ break;
+ case 'P':
+ printf("Presentation URL found:\n");
+ printf(" %s\n", data.presentationurl);
+ break;
+ default:
+ fprintf(stderr, "Unknown switch -%c\n", command);
+ retcode = 1;
+ }
+
+ FreeUPNPUrls(&urls);
+ }
+ else
+ {
+ fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
+ retcode = 1;
+ }
+ freeUPNPDevlist(devlist); devlist = 0;
+ }
+ else
+ {
+ fprintf(stderr, "No IGD UPnP Device found on the network !\n");
+ retcode = 1;
+ }
+#ifdef _WIN32
+ nResult = WSACleanup();
+ if(nResult != NO_ERROR) {
+ fprintf(stderr, "WSACleanup() failed.\n");
+ }
+#endif /* _WIN32 */
+ return retcode;
+}
+
diff --git a/ext/miniupnpc/upnpcommands.c b/ext/miniupnpc/upnpcommands.c
new file mode 100644
index 00000000..660b5d9f
--- /dev/null
+++ b/ext/miniupnpc/upnpcommands.c
@@ -0,0 +1,1238 @@
+#define _CRT_SECURE_NO_WARNINGS
+/* $Id: upnpcommands.c,v 1.46 2015/07/15 12:19:00 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "upnpcommands.h"
+#include "miniupnpc.h"
+#include "portlistingparse.h"
+
+static UNSIGNED_INTEGER
+my_atoui(const char * s)
+{
+ return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0;
+}
+
+/*
+ * */
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
+UPNP_GetTotalBytesSent(const char * controlURL,
+ const char * servicetype)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ unsigned int r = 0;
+ char * p;
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetTotalBytesSent", 0, &bufsize))) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ /*DisplayNameValueList(buffer, bufsize);*/
+ free(buffer); buffer = NULL;
+ p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent");
+ r = my_atoui(p);
+ ClearNameValueList(&pdata);
+ return r;
+}
+
+/*
+ * */
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
+UPNP_GetTotalBytesReceived(const char * controlURL,
+ const char * servicetype)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ unsigned int r = 0;
+ char * p;
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetTotalBytesReceived", 0, &bufsize))) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ /*DisplayNameValueList(buffer, bufsize);*/
+ free(buffer); buffer = NULL;
+ p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived");
+ r = my_atoui(p);
+ ClearNameValueList(&pdata);
+ return r;
+}
+
+/*
+ * */
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
+UPNP_GetTotalPacketsSent(const char * controlURL,
+ const char * servicetype)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ unsigned int r = 0;
+ char * p;
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetTotalPacketsSent", 0, &bufsize))) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ /*DisplayNameValueList(buffer, bufsize);*/
+ free(buffer); buffer = NULL;
+ p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent");
+ r = my_atoui(p);
+ ClearNameValueList(&pdata);
+ return r;
+}
+
+/*
+ * */
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
+UPNP_GetTotalPacketsReceived(const char * controlURL,
+ const char * servicetype)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ unsigned int r = 0;
+ char * p;
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetTotalPacketsReceived", 0, &bufsize))) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ /*DisplayNameValueList(buffer, bufsize);*/
+ free(buffer); buffer = NULL;
+ p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived");
+ r = my_atoui(p);
+ ClearNameValueList(&pdata);
+ return r;
+}
+
+/* UPNP_GetStatusInfo() call the corresponding UPNP method
+ * returns the current status and uptime */
+MINIUPNP_LIBSPEC int
+UPNP_GetStatusInfo(const char * controlURL,
+ const char * servicetype,
+ char * status,
+ unsigned int * uptime,
+ char * lastconnerror)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ char * p;
+ char * up;
+ char * err;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+ if(!status && !uptime)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetStatusInfo", 0, &bufsize))) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ /*DisplayNameValueList(buffer, bufsize);*/
+ free(buffer); buffer = NULL;
+ up = GetValueFromNameValueList(&pdata, "NewUptime");
+ p = GetValueFromNameValueList(&pdata, "NewConnectionStatus");
+ err = GetValueFromNameValueList(&pdata, "NewLastConnectionError");
+ if(p && up)
+ ret = UPNPCOMMAND_SUCCESS;
+
+ if(status) {
+ if(p){
+ strncpy(status, p, 64 );
+ status[63] = '\0';
+ }else
+ status[0]= '\0';
+ }
+
+ if(uptime) {
+ if(up)
+ sscanf(up,"%u",uptime);
+ else
+ *uptime = 0;
+ }
+
+ if(lastconnerror) {
+ if(err) {
+ strncpy(lastconnerror, err, 64 );
+ lastconnerror[63] = '\0';
+ } else
+ lastconnerror[0] = '\0';
+ }
+
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+ ClearNameValueList(&pdata);
+ return ret;
+}
+
+/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method
+ * returns the connection type */
+MINIUPNP_LIBSPEC int
+UPNP_GetConnectionTypeInfo(const char * controlURL,
+ const char * servicetype,
+ char * connectionType)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ char * p;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+ if(!connectionType)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetConnectionTypeInfo", 0, &bufsize))) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ p = GetValueFromNameValueList(&pdata, "NewConnectionType");
+ /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/
+ /* PossibleConnectionTypes will have several values.... */
+ if(p) {
+ strncpy(connectionType, p, 64 );
+ connectionType[63] = '\0';
+ ret = UPNPCOMMAND_SUCCESS;
+ } else
+ connectionType[0] = '\0';
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+ ClearNameValueList(&pdata);
+ return ret;
+}
+
+/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method.
+ * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth.
+ * One of the values can be null
+ * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only
+ * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */
+MINIUPNP_LIBSPEC int
+UPNP_GetLinkLayerMaxBitRates(const char * controlURL,
+ const char * servicetype,
+ unsigned int * bitrateDown,
+ unsigned int * bitrateUp)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ char * down;
+ char * up;
+ char * p;
+
+ if(!bitrateDown && !bitrateUp)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ /* shouldn't we use GetCommonLinkProperties ? */
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetCommonLinkProperties", 0, &bufsize))) {
+ /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ /*DisplayNameValueList(buffer, bufsize);*/
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/
+ /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/
+ down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate");
+ up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate");
+ /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/
+ /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/
+ if(down && up)
+ ret = UPNPCOMMAND_SUCCESS;
+
+ if(bitrateDown) {
+ if(down)
+ sscanf(down,"%u",bitrateDown);
+ else
+ *bitrateDown = 0;
+ }
+
+ if(bitrateUp) {
+ if(up)
+ sscanf(up,"%u",bitrateUp);
+ else
+ *bitrateUp = 0;
+ }
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+ ClearNameValueList(&pdata);
+ return ret;
+}
+
+
+/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
+ * if the third arg is not null the value is copied to it.
+ * at least 16 bytes must be available
+ *
+ * Return values :
+ * 0 : SUCCESS
+ * NON ZERO : ERROR Either an UPnP error code or an unknown error.
+ *
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 501 Action Failed - See UPnP Device Architecture section on Control.
+ */
+MINIUPNP_LIBSPEC int
+UPNP_GetExternalIPAddress(const char * controlURL,
+ const char * servicetype,
+ char * extIpAdd)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ char * p;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+ if(!extIpAdd || !controlURL || !servicetype)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetExternalIPAddress", 0, &bufsize))) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ /*DisplayNameValueList(buffer, bufsize);*/
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/
+ p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress");
+ if(p) {
+ strncpy(extIpAdd, p, 16 );
+ extIpAdd[15] = '\0';
+ ret = UPNPCOMMAND_SUCCESS;
+ } else
+ extIpAdd[0] = '\0';
+
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+
+ ClearNameValueList(&pdata);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
+ const char * extPort,
+ const char * inPort,
+ const char * inClient,
+ const char * desc,
+ const char * proto,
+ const char * remoteHost,
+ const char * leaseDuration)
+{
+ struct UPNParg * AddPortMappingArgs;
+ char * buffer;
+ int bufsize;
+ struct NameValueParserData pdata;
+ const char * resVal;
+ int ret;
+
+ if(!inPort || !inClient || !proto || !extPort)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
+ if(AddPortMappingArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ AddPortMappingArgs[0].elt = "NewRemoteHost";
+ AddPortMappingArgs[0].val = remoteHost;
+ AddPortMappingArgs[1].elt = "NewExternalPort";
+ AddPortMappingArgs[1].val = extPort;
+ AddPortMappingArgs[2].elt = "NewProtocol";
+ AddPortMappingArgs[2].val = proto;
+ AddPortMappingArgs[3].elt = "NewInternalPort";
+ AddPortMappingArgs[3].val = inPort;
+ AddPortMappingArgs[4].elt = "NewInternalClient";
+ AddPortMappingArgs[4].val = inClient;
+ AddPortMappingArgs[5].elt = "NewEnabled";
+ AddPortMappingArgs[5].val = "1";
+ AddPortMappingArgs[6].elt = "NewPortMappingDescription";
+ AddPortMappingArgs[6].val = desc?desc:"libminiupnpc";
+ AddPortMappingArgs[7].elt = "NewLeaseDuration";
+ AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0";
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "AddPortMapping", AddPortMappingArgs,
+ &bufsize))) {
+ free(AddPortMappingArgs);
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ /*DisplayNameValueList(buffer, bufsize);*/
+ /*buffer[bufsize] = '\0';*/
+ /*puts(buffer);*/
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ resVal = GetValueFromNameValueList(&pdata, "errorCode");
+ if(resVal) {
+ /*printf("AddPortMapping errorCode = '%s'\n", resVal); */
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(resVal, "%d", &ret);
+ } else {
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+ ClearNameValueList(&pdata);
+ free(AddPortMappingArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
+ const char * extPort,
+ const char * inPort,
+ const char * inClient,
+ const char * desc,
+ const char * proto,
+ const char * remoteHost,
+ const char * leaseDuration,
+ char * reservedPort)
+{
+ struct UPNParg * AddPortMappingArgs;
+ char * buffer;
+ int bufsize;
+ struct NameValueParserData pdata;
+ const char * resVal;
+ int ret;
+
+ if(!inPort || !inClient || !proto || !extPort)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
+ if(AddPortMappingArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ AddPortMappingArgs[0].elt = "NewRemoteHost";
+ AddPortMappingArgs[0].val = remoteHost;
+ AddPortMappingArgs[1].elt = "NewExternalPort";
+ AddPortMappingArgs[1].val = extPort;
+ AddPortMappingArgs[2].elt = "NewProtocol";
+ AddPortMappingArgs[2].val = proto;
+ AddPortMappingArgs[3].elt = "NewInternalPort";
+ AddPortMappingArgs[3].val = inPort;
+ AddPortMappingArgs[4].elt = "NewInternalClient";
+ AddPortMappingArgs[4].val = inClient;
+ AddPortMappingArgs[5].elt = "NewEnabled";
+ AddPortMappingArgs[5].val = "1";
+ AddPortMappingArgs[6].elt = "NewPortMappingDescription";
+ AddPortMappingArgs[6].val = desc?desc:"libminiupnpc";
+ AddPortMappingArgs[7].elt = "NewLeaseDuration";
+ AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0";
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "AddAnyPortMapping", AddPortMappingArgs,
+ &bufsize))) {
+ free(AddPortMappingArgs);
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ resVal = GetValueFromNameValueList(&pdata, "errorCode");
+ if(resVal) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(resVal, "%d", &ret);
+ } else {
+ char *p;
+
+ p = GetValueFromNameValueList(&pdata, "NewReservedPort");
+ if(p) {
+ strncpy(reservedPort, p, 6);
+ reservedPort[5] = '\0';
+ ret = UPNPCOMMAND_SUCCESS;
+ } else {
+ ret = UPNPCOMMAND_INVALID_RESPONSE;
+ }
+ }
+ ClearNameValueList(&pdata);
+ free(AddPortMappingArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
+ const char * extPort, const char * proto,
+ const char * remoteHost)
+{
+ /*struct NameValueParserData pdata;*/
+ struct UPNParg * DeletePortMappingArgs;
+ char * buffer;
+ int bufsize;
+ struct NameValueParserData pdata;
+ const char * resVal;
+ int ret;
+
+ if(!extPort || !proto)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg));
+ if(DeletePortMappingArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ DeletePortMappingArgs[0].elt = "NewRemoteHost";
+ DeletePortMappingArgs[0].val = remoteHost;
+ DeletePortMappingArgs[1].elt = "NewExternalPort";
+ DeletePortMappingArgs[1].val = extPort;
+ DeletePortMappingArgs[2].elt = "NewProtocol";
+ DeletePortMappingArgs[2].val = proto;
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "DeletePortMapping",
+ DeletePortMappingArgs, &bufsize))) {
+ free(DeletePortMappingArgs);
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ /*DisplayNameValueList(buffer, bufsize);*/
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ resVal = GetValueFromNameValueList(&pdata, "errorCode");
+ if(resVal) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(resVal, "%d", &ret);
+ } else {
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+ ClearNameValueList(&pdata);
+ free(DeletePortMappingArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
+ const char * extPortStart, const char * extPortEnd,
+ const char * proto,
+ const char * manage)
+{
+ struct UPNParg * DeletePortMappingArgs;
+ char * buffer;
+ int bufsize;
+ struct NameValueParserData pdata;
+ const char * resVal;
+ int ret;
+
+ if(!extPortStart || !extPortEnd || !proto || !manage)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg));
+ if(DeletePortMappingArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ DeletePortMappingArgs[0].elt = "NewStartPort";
+ DeletePortMappingArgs[0].val = extPortStart;
+ DeletePortMappingArgs[1].elt = "NewEndPort";
+ DeletePortMappingArgs[1].val = extPortEnd;
+ DeletePortMappingArgs[2].elt = "NewProtocol";
+ DeletePortMappingArgs[2].val = proto;
+ DeletePortMappingArgs[3].elt = "NewManage";
+ DeletePortMappingArgs[3].val = manage;
+
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "DeletePortMappingRange",
+ DeletePortMappingArgs, &bufsize))) {
+ free(DeletePortMappingArgs);
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ resVal = GetValueFromNameValueList(&pdata, "errorCode");
+ if(resVal) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(resVal, "%d", &ret);
+ } else {
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+ ClearNameValueList(&pdata);
+ free(DeletePortMappingArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_GetGenericPortMappingEntry(const char * controlURL,
+ const char * servicetype,
+ const char * index,
+ char * extPort,
+ char * intClient,
+ char * intPort,
+ char * protocol,
+ char * desc,
+ char * enabled,
+ char * rHost,
+ char * duration)
+{
+ struct NameValueParserData pdata;
+ struct UPNParg * GetPortMappingArgs;
+ char * buffer;
+ int bufsize;
+ char * p;
+ int r = UPNPCOMMAND_UNKNOWN_ERROR;
+ if(!index)
+ return UPNPCOMMAND_INVALID_ARGS;
+ intClient[0] = '\0';
+ intPort[0] = '\0';
+ GetPortMappingArgs = calloc(2, sizeof(struct UPNParg));
+ if(GetPortMappingArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ GetPortMappingArgs[0].elt = "NewPortMappingIndex";
+ GetPortMappingArgs[0].val = index;
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetGenericPortMappingEntry",
+ GetPortMappingArgs, &bufsize))) {
+ free(GetPortMappingArgs);
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+
+ p = GetValueFromNameValueList(&pdata, "NewRemoteHost");
+ if(p && rHost)
+ {
+ strncpy(rHost, p, 64);
+ rHost[63] = '\0';
+ }
+ p = GetValueFromNameValueList(&pdata, "NewExternalPort");
+ if(p && extPort)
+ {
+ strncpy(extPort, p, 6);
+ extPort[5] = '\0';
+ r = UPNPCOMMAND_SUCCESS;
+ }
+ p = GetValueFromNameValueList(&pdata, "NewProtocol");
+ if(p && protocol)
+ {
+ strncpy(protocol, p, 4);
+ protocol[3] = '\0';
+ }
+ p = GetValueFromNameValueList(&pdata, "NewInternalClient");
+ if(p && intClient)
+ {
+ strncpy(intClient, p, 16);
+ intClient[15] = '\0';
+ r = 0;
+ }
+ p = GetValueFromNameValueList(&pdata, "NewInternalPort");
+ if(p && intPort)
+ {
+ strncpy(intPort, p, 6);
+ intPort[5] = '\0';
+ }
+ p = GetValueFromNameValueList(&pdata, "NewEnabled");
+ if(p && enabled)
+ {
+ strncpy(enabled, p, 4);
+ enabled[3] = '\0';
+ }
+ p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription");
+ if(p && desc)
+ {
+ strncpy(desc, p, 80);
+ desc[79] = '\0';
+ }
+ p = GetValueFromNameValueList(&pdata, "NewLeaseDuration");
+ if(p && duration)
+ {
+ strncpy(duration, p, 16);
+ duration[15] = '\0';
+ }
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p) {
+ r = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &r);
+ }
+ ClearNameValueList(&pdata);
+ free(GetPortMappingArgs);
+ return r;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
+ const char * servicetype,
+ unsigned int * numEntries)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ char* p;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetPortMappingNumberOfEntries", 0,
+ &bufsize))) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+#ifdef DEBUG
+ DisplayNameValueList(buffer, bufsize);
+#endif
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+
+ p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries");
+ if(numEntries && p) {
+ *numEntries = 0;
+ sscanf(p, "%u", numEntries);
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+
+ ClearNameValueList(&pdata);
+ return ret;
+}
+
+/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
+ * the result is returned in the intClient and intPort strings
+ * please provide 16 and 6 bytes of data */
+MINIUPNP_LIBSPEC int
+UPNP_GetSpecificPortMappingEntry(const char * controlURL,
+ const char * servicetype,
+ const char * extPort,
+ const char * proto,
+ const char * remoteHost,
+ char * intClient,
+ char * intPort,
+ char * desc,
+ char * enabled,
+ char * leaseDuration)
+{
+ struct NameValueParserData pdata;
+ struct UPNParg * GetPortMappingArgs;
+ char * buffer;
+ int bufsize;
+ char * p;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+ if(!intPort || !intClient || !extPort || !proto)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
+ if(GetPortMappingArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ GetPortMappingArgs[0].elt = "NewRemoteHost";
+ GetPortMappingArgs[0].val = remoteHost;
+ GetPortMappingArgs[1].elt = "NewExternalPort";
+ GetPortMappingArgs[1].val = extPort;
+ GetPortMappingArgs[2].elt = "NewProtocol";
+ GetPortMappingArgs[2].val = proto;
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetSpecificPortMappingEntry",
+ GetPortMappingArgs, &bufsize))) {
+ free(GetPortMappingArgs);
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ /*DisplayNameValueList(buffer, bufsize);*/
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+
+ p = GetValueFromNameValueList(&pdata, "NewInternalClient");
+ if(p) {
+ strncpy(intClient, p, 16);
+ intClient[15] = '\0';
+ ret = UPNPCOMMAND_SUCCESS;
+ } else
+ intClient[0] = '\0';
+
+ p = GetValueFromNameValueList(&pdata, "NewInternalPort");
+ if(p) {
+ strncpy(intPort, p, 6);
+ intPort[5] = '\0';
+ } else
+ intPort[0] = '\0';
+
+ p = GetValueFromNameValueList(&pdata, "NewEnabled");
+ if(p && enabled) {
+ strncpy(enabled, p, 4);
+ enabled[3] = '\0';
+ }
+
+ p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription");
+ if(p && desc) {
+ strncpy(desc, p, 80);
+ desc[79] = '\0';
+ }
+
+ p = GetValueFromNameValueList(&pdata, "NewLeaseDuration");
+ if(p && leaseDuration)
+ {
+ strncpy(leaseDuration, p, 16);
+ leaseDuration[15] = '\0';
+ }
+
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+
+ ClearNameValueList(&pdata);
+ free(GetPortMappingArgs);
+ return ret;
+}
+
+/* UPNP_GetListOfPortMappings()
+ *
+ * Possible UPNP Error codes :
+ * 606 Action not Authorized
+ * 730 PortMappingNotFound - no port mapping is found in the specified range.
+ * 733 InconsistantParameters - NewStartPort and NewEndPort values are not
+ * consistent.
+ */
+MINIUPNP_LIBSPEC int
+UPNP_GetListOfPortMappings(const char * controlURL,
+ const char * servicetype,
+ const char * startPort,
+ const char * endPort,
+ const char * protocol,
+ const char * numberOfPorts,
+ struct PortMappingParserData * data)
+{
+ struct NameValueParserData pdata;
+ struct UPNParg * GetListOfPortMappingsArgs;
+ const char * p;
+ char * buffer;
+ int bufsize;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+ if(!startPort || !endPort || !protocol)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg));
+ if(GetListOfPortMappingsArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ GetListOfPortMappingsArgs[0].elt = "NewStartPort";
+ GetListOfPortMappingsArgs[0].val = startPort;
+ GetListOfPortMappingsArgs[1].elt = "NewEndPort";
+ GetListOfPortMappingsArgs[1].val = endPort;
+ GetListOfPortMappingsArgs[2].elt = "NewProtocol";
+ GetListOfPortMappingsArgs[2].val = protocol;
+ GetListOfPortMappingsArgs[3].elt = "NewManage";
+ GetListOfPortMappingsArgs[3].val = "1";
+ GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts";
+ GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000";
+
+ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetListOfPortMappings",
+ GetListOfPortMappingsArgs, &bufsize))) {
+ free(GetListOfPortMappingsArgs);
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ free(GetListOfPortMappingsArgs);
+
+ /*DisplayNameValueList(buffer, bufsize);*/
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+
+ /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/
+ /*if(p) {
+ printf("NewPortListing : %s\n", p);
+ }*/
+ /*printf("NewPortListing(%d chars) : %s\n",
+ pdata.portListingLength, pdata.portListing);*/
+ if(pdata.portListing)
+ {
+ /*struct PortMapping * pm;
+ int i = 0;*/
+ ParsePortListing(pdata.portListing, pdata.portListingLength,
+ data);
+ ret = UPNPCOMMAND_SUCCESS;
+ /*
+ for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next)
+ {
+ printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n",
+ i, pm->protocol, pm->externalPort, pm->internalClient,
+ pm->internalPort,
+ pm->description, pm->remoteHost);
+ i++;
+ }
+ */
+ /*FreePortListing(&data);*/
+ }
+
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p) {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+ ClearNameValueList(&pdata);
+
+ /*printf("%.*s", bufsize, buffer);*/
+
+ return ret;
+}
+
+/* IGD:2, functions for service WANIPv6FirewallControl:1 */
+MINIUPNP_LIBSPEC int
+UPNP_GetFirewallStatus(const char * controlURL,
+ const char * servicetype,
+ int * firewallEnabled,
+ int * inboundPinholeAllowed)
+{
+ struct NameValueParserData pdata;
+ char * buffer;
+ int bufsize;
+ char * fe, *ipa, *p;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+ if(!firewallEnabled || !inboundPinholeAllowed)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetFirewallStatus", 0, &bufsize);
+ if(!buffer) {
+ return UPNPCOMMAND_HTTP_ERROR;
+ }
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ fe = GetValueFromNameValueList(&pdata, "FirewallEnabled");
+ ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed");
+ if(ipa && fe)
+ ret = UPNPCOMMAND_SUCCESS;
+ if(fe)
+ *firewallEnabled = my_atoui(fe);
+ /*else
+ *firewallEnabled = 0;*/
+ if(ipa)
+ *inboundPinholeAllowed = my_atoui(ipa);
+ /*else
+ *inboundPinholeAllowed = 0;*/
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p)
+ {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+ ClearNameValueList(&pdata);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
+ const char * remoteHost,
+ const char * remotePort,
+ const char * intClient,
+ const char * intPort,
+ const char * proto,
+ int * opTimeout)
+{
+ struct UPNParg * GetOutboundPinholeTimeoutArgs;
+ char * buffer;
+ int bufsize;
+ struct NameValueParserData pdata;
+ const char * resVal;
+ char * p;
+ int ret;
+
+ if(!intPort || !intClient || !proto || !remotePort || !remoteHost)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg));
+ if(GetOutboundPinholeTimeoutArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost";
+ GetOutboundPinholeTimeoutArgs[0].val = remoteHost;
+ GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort";
+ GetOutboundPinholeTimeoutArgs[1].val = remotePort;
+ GetOutboundPinholeTimeoutArgs[2].elt = "Protocol";
+ GetOutboundPinholeTimeoutArgs[2].val = proto;
+ GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort";
+ GetOutboundPinholeTimeoutArgs[3].val = intPort;
+ GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient";
+ GetOutboundPinholeTimeoutArgs[4].val = intClient;
+ buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize);
+ if(!buffer)
+ return UPNPCOMMAND_HTTP_ERROR;
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ resVal = GetValueFromNameValueList(&pdata, "errorCode");
+ if(resVal)
+ {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(resVal, "%d", &ret);
+ }
+ else
+ {
+ ret = UPNPCOMMAND_SUCCESS;
+ p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout");
+ if(p)
+ *opTimeout = my_atoui(p);
+ }
+ ClearNameValueList(&pdata);
+ free(GetOutboundPinholeTimeoutArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_AddPinhole(const char * controlURL, const char * servicetype,
+ const char * remoteHost,
+ const char * remotePort,
+ const char * intClient,
+ const char * intPort,
+ const char * proto,
+ const char * leaseTime,
+ char * uniqueID)
+{
+ struct UPNParg * AddPinholeArgs;
+ char * buffer;
+ int bufsize;
+ struct NameValueParserData pdata;
+ const char * resVal;
+ char * p;
+ int ret;
+
+ if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ AddPinholeArgs = calloc(7, sizeof(struct UPNParg));
+ if(AddPinholeArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ /* RemoteHost can be wilcarded */
+ if(strncmp(remoteHost, "empty", 5)==0)
+ {
+ AddPinholeArgs[0].elt = "RemoteHost";
+ AddPinholeArgs[0].val = "";
+ }
+ else
+ {
+ AddPinholeArgs[0].elt = "RemoteHost";
+ AddPinholeArgs[0].val = remoteHost;
+ }
+ AddPinholeArgs[1].elt = "RemotePort";
+ AddPinholeArgs[1].val = remotePort;
+ AddPinholeArgs[2].elt = "Protocol";
+ AddPinholeArgs[2].val = proto;
+ AddPinholeArgs[3].elt = "InternalPort";
+ AddPinholeArgs[3].val = intPort;
+ if(strncmp(intClient, "empty", 5)==0)
+ {
+ AddPinholeArgs[4].elt = "InternalClient";
+ AddPinholeArgs[4].val = "";
+ }
+ else
+ {
+ AddPinholeArgs[4].elt = "InternalClient";
+ AddPinholeArgs[4].val = intClient;
+ }
+ AddPinholeArgs[5].elt = "LeaseTime";
+ AddPinholeArgs[5].val = leaseTime;
+ buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "AddPinhole", AddPinholeArgs, &bufsize);
+ if(!buffer)
+ return UPNPCOMMAND_HTTP_ERROR;
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ p = GetValueFromNameValueList(&pdata, "UniqueID");
+ if(p)
+ {
+ strncpy(uniqueID, p, 8);
+ uniqueID[7] = '\0';
+ }
+ resVal = GetValueFromNameValueList(&pdata, "errorCode");
+ if(resVal)
+ {
+ /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(resVal, "%d", &ret);
+ }
+ else
+ {
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+ ClearNameValueList(&pdata);
+ free(AddPinholeArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
+ const char * uniqueID,
+ const char * leaseTime)
+{
+ struct UPNParg * UpdatePinholeArgs;
+ char * buffer;
+ int bufsize;
+ struct NameValueParserData pdata;
+ const char * resVal;
+ int ret;
+
+ if(!uniqueID || !leaseTime)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg));
+ if(UpdatePinholeArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ UpdatePinholeArgs[0].elt = "UniqueID";
+ UpdatePinholeArgs[0].val = uniqueID;
+ UpdatePinholeArgs[1].elt = "NewLeaseTime";
+ UpdatePinholeArgs[1].val = leaseTime;
+ buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "UpdatePinhole", UpdatePinholeArgs, &bufsize);
+ if(!buffer)
+ return UPNPCOMMAND_HTTP_ERROR;
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ resVal = GetValueFromNameValueList(&pdata, "errorCode");
+ if(resVal)
+ {
+ /*printf("AddPortMapping errorCode = '%s'\n", resVal); */
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(resVal, "%d", &ret);
+ }
+ else
+ {
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+ ClearNameValueList(&pdata);
+ free(UpdatePinholeArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID)
+{
+ /*struct NameValueParserData pdata;*/
+ struct UPNParg * DeletePinholeArgs;
+ char * buffer;
+ int bufsize;
+ struct NameValueParserData pdata;
+ const char * resVal;
+ int ret;
+
+ if(!uniqueID)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ DeletePinholeArgs = calloc(2, sizeof(struct UPNParg));
+ if(DeletePinholeArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ DeletePinholeArgs[0].elt = "UniqueID";
+ DeletePinholeArgs[0].val = uniqueID;
+ buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "DeletePinhole", DeletePinholeArgs, &bufsize);
+ if(!buffer)
+ return UPNPCOMMAND_HTTP_ERROR;
+ /*DisplayNameValueList(buffer, bufsize);*/
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+ resVal = GetValueFromNameValueList(&pdata, "errorCode");
+ if(resVal)
+ {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(resVal, "%d", &ret);
+ }
+ else
+ {
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+ ClearNameValueList(&pdata);
+ free(DeletePinholeArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
+ const char * uniqueID, int * isWorking)
+{
+ struct NameValueParserData pdata;
+ struct UPNParg * CheckPinholeWorkingArgs;
+ char * buffer;
+ int bufsize;
+ char * p;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+ if(!uniqueID)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg));
+ if(CheckPinholeWorkingArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ CheckPinholeWorkingArgs[0].elt = "UniqueID";
+ CheckPinholeWorkingArgs[0].val = uniqueID;
+ buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize);
+ if(!buffer)
+ return UPNPCOMMAND_HTTP_ERROR;
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+
+ p = GetValueFromNameValueList(&pdata, "IsWorking");
+ if(p)
+ {
+ *isWorking=my_atoui(p);
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+ else
+ *isWorking = 0;
+
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p)
+ {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+
+ ClearNameValueList(&pdata);
+ free(CheckPinholeWorkingArgs);
+ return ret;
+}
+
+MINIUPNP_LIBSPEC int
+UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
+ const char * uniqueID, int * packets)
+{
+ struct NameValueParserData pdata;
+ struct UPNParg * GetPinholePacketsArgs;
+ char * buffer;
+ int bufsize;
+ char * p;
+ int ret = UPNPCOMMAND_UNKNOWN_ERROR;
+
+ if(!uniqueID)
+ return UPNPCOMMAND_INVALID_ARGS;
+
+ GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg));
+ if(GetPinholePacketsArgs == NULL)
+ return UPNPCOMMAND_MEM_ALLOC_ERROR;
+ GetPinholePacketsArgs[0].elt = "UniqueID";
+ GetPinholePacketsArgs[0].val = uniqueID;
+ buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+ "GetPinholePackets", GetPinholePacketsArgs, &bufsize);
+ if(!buffer)
+ return UPNPCOMMAND_HTTP_ERROR;
+ ParseNameValue(buffer, bufsize, &pdata);
+ free(buffer); buffer = NULL;
+
+ p = GetValueFromNameValueList(&pdata, "PinholePackets");
+ if(p)
+ {
+ *packets=my_atoui(p);
+ ret = UPNPCOMMAND_SUCCESS;
+ }
+
+ p = GetValueFromNameValueList(&pdata, "errorCode");
+ if(p)
+ {
+ ret = UPNPCOMMAND_UNKNOWN_ERROR;
+ sscanf(p, "%d", &ret);
+ }
+
+ ClearNameValueList(&pdata);
+ free(GetPinholePacketsArgs);
+ return ret;
+}
+
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h b/ext/miniupnpc/upnpcommands.h
index 22eda5e3..22eda5e3 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h
+++ b/ext/miniupnpc/upnpcommands.h
diff --git a/ext/miniupnpc/upnpdev.c b/ext/miniupnpc/upnpdev.c
new file mode 100644
index 00000000..d89a9934
--- /dev/null
+++ b/ext/miniupnpc/upnpdev.c
@@ -0,0 +1,23 @@
+/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
+/* Project : miniupnp
+ * Web : http://miniupnp.free.fr/
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENSE file. */
+#include <stdlib.h>
+#include "upnpdev.h"
+
+/* freeUPNPDevlist() should be used to
+ * free the chained list returned by upnpDiscover() */
+void freeUPNPDevlist(struct UPNPDev * devlist)
+{
+ struct UPNPDev * next;
+ while(devlist)
+ {
+ next = devlist->pNext;
+ free(devlist);
+ devlist = next;
+ }
+}
+
diff --git a/ext/miniupnpc/upnpdev.h b/ext/miniupnpc/upnpdev.h
new file mode 100644
index 00000000..f49fbe17
--- /dev/null
+++ b/ext/miniupnpc/upnpdev.h
@@ -0,0 +1,36 @@
+/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
+/* Project : miniupnp
+ * Web : http://miniupnp.free.fr/
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENSE file. */
+#ifndef UPNPDEV_H_INCLUDED
+#define UPNPDEV_H_INCLUDED
+
+#include "miniupnpc_declspec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct UPNPDev {
+ struct UPNPDev * pNext;
+ char * descURL;
+ char * st;
+ unsigned int scope_id;
+ char * usn;
+ char buffer[3];
+};
+
+/* freeUPNPDevlist()
+ * free list returned by upnpDiscover() */
+MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* UPNPDEV_H_INCLUDED */
diff --git a/ext/miniupnpc/upnperrors.c b/ext/miniupnpc/upnperrors.c
new file mode 100644
index 00000000..7ab8ee96
--- /dev/null
+++ b/ext/miniupnpc/upnperrors.c
@@ -0,0 +1,107 @@
+/* $Id: upnperrors.c,v 1.8 2014/06/10 09:41:48 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas BERNARD
+ * copyright (c) 2007 Thomas Bernard
+ * All Right reserved.
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * This software is subjet to the conditions detailed in the
+ * provided LICENCE file. */
+#include <string.h>
+#include "upnperrors.h"
+#include "upnpcommands.h"
+#include "miniupnpc.h"
+
+const char * strupnperror(int err)
+{
+ const char * s = NULL;
+ switch(err) {
+ case UPNPCOMMAND_SUCCESS:
+ s = "Success";
+ break;
+ case UPNPCOMMAND_UNKNOWN_ERROR:
+ s = "Miniupnpc Unknown Error";
+ break;
+ case UPNPCOMMAND_INVALID_ARGS:
+ s = "Miniupnpc Invalid Arguments";
+ break;
+ case UPNPCOMMAND_INVALID_RESPONSE:
+ s = "Miniupnpc Invalid response";
+ break;
+ case UPNPDISCOVER_SOCKET_ERROR:
+ s = "Miniupnpc Socket error";
+ break;
+ case UPNPDISCOVER_MEMORY_ERROR:
+ s = "Miniupnpc Memory allocation error";
+ break;
+ case 401:
+ s = "Invalid Action";
+ break;
+ case 402:
+ s = "Invalid Args";
+ break;
+ case 501:
+ s = "Action Failed";
+ break;
+ case 606:
+ s = "Action not authorized";
+ break;
+ case 701:
+ s = "PinholeSpaceExhausted";
+ break;
+ case 702:
+ s = "FirewallDisabled";
+ break;
+ case 703:
+ s = "InboundPinholeNotAllowed";
+ break;
+ case 704:
+ s = "NoSuchEntry";
+ break;
+ case 705:
+ s = "ProtocolNotSupported";
+ break;
+ case 706:
+ s = "InternalPortWildcardingNotAllowed";
+ break;
+ case 707:
+ s = "ProtocolWildcardingNotAllowed";
+ break;
+ case 708:
+ s = "WildcardNotPermittedInSrcIP";
+ break;
+ case 709:
+ s = "NoPacketSent";
+ break;
+ case 713:
+ s = "SpecifiedArrayIndexInvalid";
+ break;
+ case 714:
+ s = "NoSuchEntryInArray";
+ break;
+ case 715:
+ s = "WildCardNotPermittedInSrcIP";
+ break;
+ case 716:
+ s = "WildCardNotPermittedInExtPort";
+ break;
+ case 718:
+ s = "ConflictInMappingEntry";
+ break;
+ case 724:
+ s = "SamePortValuesRequired";
+ break;
+ case 725:
+ s = "OnlyPermanentLeasesSupported";
+ break;
+ case 726:
+ s = "RemoteHostOnlySupportsWildcard";
+ break;
+ case 727:
+ s = "ExternalPortOnlySupportsWildcard";
+ break;
+ default:
+ s = "UnknownError";
+ break;
+ }
+ return s;
+}
diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h b/ext/miniupnpc/upnperrors.h
index 3115aee5..3115aee5 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h
+++ b/ext/miniupnpc/upnperrors.h
diff --git a/ext/miniupnpc/upnpreplyparse.c b/ext/miniupnpc/upnpreplyparse.c
new file mode 100644
index 00000000..88d77a66
--- /dev/null
+++ b/ext/miniupnpc/upnpreplyparse.c
@@ -0,0 +1,198 @@
+#define _CRT_SECURE_NO_WARNINGS
+/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
+/* MiniUPnP project
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * (c) 2006-2015 Thomas Bernard
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "upnpreplyparse.h"
+#include "minixml.h"
+
+static void
+NameValueParserStartElt(void * d, const char * name, int l)
+{
+ struct NameValueParserData * data = (struct NameValueParserData *)d;
+ data->topelt = 1;
+ if(l>63)
+ l = 63;
+ memcpy(data->curelt, name, l);
+ data->curelt[l] = '\0';
+ data->cdata = NULL;
+ data->cdatalen = 0;
+}
+
+static void
+NameValueParserEndElt(void * d, const char * name, int l)
+{
+ struct NameValueParserData * data = (struct NameValueParserData *)d;
+ struct NameValue * nv;
+ (void)name;
+ (void)l;
+ if(!data->topelt)
+ return;
+ if(strcmp(data->curelt, "NewPortListing") != 0)
+ {
+ int l;
+ /* standard case. Limited to n chars strings */
+ l = data->cdatalen;
+ nv = malloc(sizeof(struct NameValue));
+ if(nv == NULL)
+ {
+ /* malloc error */
+#ifdef DEBUG
+ fprintf(stderr, "%s: error allocating memory",
+ "NameValueParserEndElt");
+#endif /* DEBUG */
+ return;
+ }
+ if(l>=(int)sizeof(nv->value))
+ l = sizeof(nv->value) - 1;
+ strncpy(nv->name, data->curelt, 64);
+ nv->name[63] = '\0';
+ if(data->cdata != NULL)
+ {
+ memcpy(nv->value, data->cdata, l);
+ nv->value[l] = '\0';
+ }
+ else
+ {
+ nv->value[0] = '\0';
+ }
+ nv->l_next = data->l_head; /* insert in list */
+ data->l_head = nv;
+ }
+ data->cdata = NULL;
+ data->cdatalen = 0;
+ data->topelt = 0;
+}
+
+static void
+NameValueParserGetData(void * d, const char * datas, int l)
+{
+ struct NameValueParserData * data = (struct NameValueParserData *)d;
+ if(strcmp(data->curelt, "NewPortListing") == 0)
+ {
+ /* specific case for NewPortListing which is a XML Document */
+ data->portListing = malloc(l + 1);
+ if(!data->portListing)
+ {
+ /* malloc error */
+#ifdef DEBUG
+ fprintf(stderr, "%s: error allocating memory",
+ "NameValueParserGetData");
+#endif /* DEBUG */
+ return;
+ }
+ memcpy(data->portListing, datas, l);
+ data->portListing[l] = '\0';
+ data->portListingLength = l;
+ }
+ else
+ {
+ /* standard case. */
+ data->cdata = datas;
+ data->cdatalen = l;
+ }
+}
+
+void
+ParseNameValue(const char * buffer, int bufsize,
+ struct NameValueParserData * data)
+{
+ struct xmlparser parser;
+ data->l_head = NULL;
+ data->portListing = NULL;
+ data->portListingLength = 0;
+ /* init xmlparser object */
+ parser.xmlstart = buffer;
+ parser.xmlsize = bufsize;
+ parser.data = data;
+ parser.starteltfunc = NameValueParserStartElt;
+ parser.endeltfunc = NameValueParserEndElt;
+ parser.datafunc = NameValueParserGetData;
+ parser.attfunc = 0;
+ parsexml(&parser);
+}
+
+void
+ClearNameValueList(struct NameValueParserData * pdata)
+{
+ struct NameValue * nv;
+ if(pdata->portListing)
+ {
+ free(pdata->portListing);
+ pdata->portListing = NULL;
+ pdata->portListingLength = 0;
+ }
+ while((nv = pdata->l_head) != NULL)
+ {
+ pdata->l_head = nv->l_next;
+ free(nv);
+ }
+}
+
+char *
+GetValueFromNameValueList(struct NameValueParserData * pdata,
+ const char * Name)
+{
+ struct NameValue * nv;
+ char * p = NULL;
+ for(nv = pdata->l_head;
+ (nv != NULL) && (p == NULL);
+ nv = nv->l_next)
+ {
+ if(strcmp(nv->name, Name) == 0)
+ p = nv->value;
+ }
+ return p;
+}
+
+#if 0
+/* useless now that minixml ignores namespaces by itself */
+char *
+GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
+ const char * Name)
+{
+ struct NameValue * nv;
+ char * p = NULL;
+ char * pname;
+ for(nv = pdata->head.lh_first;
+ (nv != NULL) && (p == NULL);
+ nv = nv->entries.le_next)
+ {
+ pname = strrchr(nv->name, ':');
+ if(pname)
+ pname++;
+ else
+ pname = nv->name;
+ if(strcmp(pname, Name)==0)
+ p = nv->value;
+ }
+ return p;
+}
+#endif
+
+/* debug all-in-one function
+ * do parsing then display to stdout */
+#ifdef DEBUG
+void
+DisplayNameValueList(char * buffer, int bufsize)
+{
+ struct NameValueParserData pdata;
+ struct NameValue * nv;
+ ParseNameValue(buffer, bufsize, &pdata);
+ for(nv = pdata.l_head;
+ nv != NULL;
+ nv = nv->l_next)
+ {
+ printf("%s = %s\n", nv->name, nv->value);
+ }
+ ClearNameValueList(&pdata);
+}
+#endif /* DEBUG */
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h b/ext/miniupnpc/upnpreplyparse.h
index 6badd15b..6badd15b 100644
--- a/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h
+++ b/ext/miniupnpc/upnpreplyparse.h
diff --git a/ext/miniupnpc/wingenminiupnpcstrings.c b/ext/miniupnpc/wingenminiupnpcstrings.c
new file mode 100644
index 00000000..50df06a7
--- /dev/null
+++ b/ext/miniupnpc/wingenminiupnpcstrings.c
@@ -0,0 +1,83 @@
+/* $Id: wingenminiupnpcstrings.c,v 1.4 2015/02/08 08:46:06 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENSE file provided within this distribution */
+#include <stdio.h>
+#include <windows.h>
+
+/* This program display the Windows version and is used to
+ * generate the miniupnpcstrings.h
+ * wingenminiupnpcstrings miniupnpcstrings.h.in miniupnpcstrings.h
+ */
+int main(int argc, char * * argv) {
+ char buffer[256];
+ OSVERSIONINFO osvi;
+ FILE * fin;
+ FILE * fout;
+ int n;
+ char miniupnpcVersion[32];
+ /* dwMajorVersion :
+ The major version number of the operating system. For more information, see Remarks.
+ dwMinorVersion :
+ The minor version number of the operating system. For more information, see Remarks.
+ dwBuildNumber :
+ The build number of the operating system.
+ dwPlatformId
+ The operating system platform. This member can be the following value.
+ szCSDVersion
+ A null-terminated string, such as "Service Pack 3", that indicates the
+ latest Service Pack installed on the system. If no Service Pack has
+ been installed, the string is empty.
+ */
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ GetVersionEx(&osvi);
+
+ printf("Windows %lu.%lu Build %lu %s\n",
+ osvi.dwMajorVersion, osvi.dwMinorVersion,
+ osvi.dwBuildNumber, (const char *)&(osvi.szCSDVersion));
+
+ fin = fopen("VERSION", "r");
+ fgets(miniupnpcVersion, sizeof(miniupnpcVersion), fin);
+ fclose(fin);
+ for(n = 0; n < sizeof(miniupnpcVersion); n++) {
+ if(miniupnpcVersion[n] < ' ')
+ miniupnpcVersion[n] = '\0';
+ }
+ printf("MiniUPnPc version %s\n", miniupnpcVersion);
+
+ if(argc >= 3) {
+ fin = fopen(argv[1], "r");
+ if(!fin) {
+ fprintf(stderr, "Cannot open %s for reading.\n", argv[1]);
+ return 1;
+ }
+ fout = fopen(argv[2], "w");
+ if(!fout) {
+ fprintf(stderr, "Cannot open %s for writing.\n", argv[2]);
+ fclose(fin);
+ return 1;
+ }
+ n = 0;
+ while(fgets(buffer, sizeof(buffer), fin)) {
+ if(0 == memcmp(buffer, "#define OS_STRING \"OS/version\"", 30)) {
+ sprintf(buffer, "#define OS_STRING \"MSWindows/%ld.%ld.%ld\"\n",
+ osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
+ } else if(0 == memcmp(buffer, "#define MINIUPNPC_VERSION_STRING \"version\"", 42)) {
+ sprintf(buffer, "#define MINIUPNPC_VERSION_STRING \"%s\"\n",
+ miniupnpcVersion);
+ }
+ /*fputs(buffer, stdout);*/
+ fputs(buffer, fout);
+ n++;
+ }
+ fclose(fin);
+ fclose(fout);
+ printf("%d lines written to %s.\n", n, argv[2]);
+ }
+ return 0;
+}
diff --git a/ext/tap-mac/tuntap/Makefile b/ext/tap-mac/tuntap/Makefile
index 8d79577e..53ab1a9d 100644
--- a/ext/tap-mac/tuntap/Makefile
+++ b/ext/tap-mac/tuntap/Makefile
@@ -1,12 +1,95 @@
-TUNTAP_VERSION = 20131028
+# Lets have a version, at last!
+TUNTAP_VERSION = 20150118
+
+# BASE install directory
BASE=
all: tap.kext
+keysetup:
+ -security delete-keychain net.sf.tuntaposx.tmp
+ security create-keychain -p $$(head -c 32 /dev/urandom | hexdump -e '"%02x"') \
+ net.sf.tuntaposx.tmp
+ security set-keychain-settings -lut 60 net.sf.tuntaposx.tmp
+ security import identity.p12 -k net.sf.tuntaposx.tmp -f pkcs12 \
+ -P $$(read -sp 'identity passphrase: ' pw && echo "$$pw") -A
+ security find-identity -v net.sf.tuntaposx.tmp | \
+ awk -F \" '$$2 ~ /^Developer ID Application:/ { print $$2 }' > .signing_identity
+ security find-identity -v net.sf.tuntaposx.tmp | \
+ awk -F \" '$$2 ~ /^Developer ID Installer:/ { print $$2 }' > .installer_identity
+
+pkgbuild/%.pkg: %.kext
+ mkdir -p pkgbuild/$*_root/Library/Extensions
+ cp -pR $*.kext pkgbuild/$*_root/Library/Extensions
+ mkdir -p pkgbuild/$*_root/Library/LaunchDaemons
+ cp pkg/launchd/net.sf.tuntaposx.$*.plist pkgbuild/$*_root/Library/LaunchDaemons
+ pkgbuild --root pkgbuild/$*_root \
+ --component-plist pkg/components/$*.plist \
+ --scripts pkg/scripts/$* pkgbuild/$*.pkg
+
+tuntap_$(TUNTAP_VERSION).pkg: pkgbuild/tap.pkg pkgbuild/tun.pkg
+ productbuild --distribution pkg/distribution.xml --package-path pkgbuild \
+ --resources pkg/res.dummy \
+ tuntap_$(TUNTAP_VERSION).pkg ; \
+ pkgutil --expand tuntap_$(TUNTAP_VERSION).pkg pkgbuild/tuntap_pkg.d
+ cp -pR pkg/res/ pkgbuild/tuntap_pkg.d/Resources
+ pkgutil --flatten pkgbuild/tuntap_pkg.d tuntap_$(TUNTAP_VERSION).pkg
+ if test -s ".installer_identity"; then \
+ productsign --sign "$$(cat .installer_identity)" --keychain net.sf.tuntaposx.tmp \
+ tuntap_$(TUNTAP_VERSION).pkg tuntap_$(TUNTAP_VERSION).pkg.signed ; \
+ mv tuntap_$(TUNTAP_VERSION).pkg.signed tuntap_$(TUNTAP_VERSION).pkg ; \
+ fi
+
+pkg: tuntap_$(TUNTAP_VERSION).pkg
+ tar czf tuntap_$(TUNTAP_VERSION).tar.gz \
+ README.installer README tuntap_$(TUNTAP_VERSION).pkg
+
+# Install targets
+# They are provided for the gentoo ebuild, but should work just fine for other people as well.
+install_%_kext: %.kext
+ mkdir -p $(BASE)/Library/Extensions
+ cp -pR $*.kext $(BASE)/Library/Extensions/
+ chown -R root:wheel $(BASE)/Library/Extensions/$*.kext
+ mkdir -p $(BASE)/Library/LaunchDaemons
+ cp pkg/launchd/net.sf.tuntaposx.$*.plist $(BASE)/Library/LaunchDaemons
+ chown -R root:wheel $(BASE)/Library/LaunchDaemons/net.sf.tuntaposx.$*.plist
+
+install: install_tap_kext install_tun_kext
+
+tarball: clean
+ touch tuntap_$(TUNTAP_VERSION)_src.tar.gz
+ tar czf tuntap_$(TUNTAP_VERSION)_src.tar.gz \
+ -C .. \
+ --exclude "tuntap/identity.p12" \
+ --exclude "tuntap/tuntap_$(TUNTAP_VERSION)_src.tar.gz" \
+ --exclude "tuntap/tuntap_$(TUNTAP_VERSION).tar.gz" \
+ --exclude "tuntap/tuntap_$(TUNTAP_VERSION).pkg" \
+ --exclude "*/.*" \
+ tuntap
+
clean:
cd src/tap && make -f Makefile clean
+ cd src/tun && make -f Makefile clean
+ -rm -rf pkgbuild
+ -rm -rf tuntap_$(TUNTAP_VERSION).pkg
+ -rm -f tuntap_$(TUNTAP_VERSION).tar.gz
+ -rm -f tuntap_$(TUNTAP_VERSION)_src.tar.gz
+
+%.kext:
+ cd src/$* && make TUNTAP_VERSION=$(TUNTAP_VERSION) -f Makefile all
+ if test -s ".signing_identity"; then \
+ codesign -fv --keychain net.sf.tuntaposx.tmp -s "$$(cat .signing_identity)" \
+ $*.kext ; \
+ fi
-tap.kext:
- cd src/tap && make TUNTAP_VERSION=$(TUNTAP_VERSION) -f Makefile all
+test:
+ # configd messes with interface flags, issuing SIOCSIFFLAGS ioctls upon receiving kernel
+ # events indicating protocols have been attached and detached. Unfortunately, configd does
+ # this asynchronously, making the SIOCSIFFLAGS changes totally unpredictable when we bring
+ # our interfaces up and down in rapid succession during our tests. I haven't found a good
+ # way to suppress or handle this mess other than disabling configd temporarily.
+ killall -STOP configd
+ -PYTHONPATH=test python test/tuntap/tuntap_tests.py --tests='$(TESTS)'
+ killall -CONT configd
.PHONY: test
diff --git a/ext/tap-mac/tuntap/README.orig b/ext/tap-mac/tuntap/README.orig
deleted file mode 100644
index 6a9e526b..00000000
--- a/ext/tap-mac/tuntap/README.orig
+++ /dev/null
@@ -1,85 +0,0 @@
-
-tun/tap driver for Mac OS X
-===========================
-
-This is an experimental IP tunnel/ethertap driver for Mac OS X/Darwin. It
-provides /dev/tunX and /dev/tapX devices. The maximum number of devices can be
-configured at compile time, it is currently set to 16. That should be enough in
-most cases.
-
-The driver ships as two kernel extensions, one for tap and one for tun. They are
-located in /Library/Extensions and can also be loaded and unloaded by hand. If
-you install the startup item, the system will load them automatically at
-startup (tun and tap startup items get installed in /Library/StartupItems).
-
-Operation & Programming notes
-=============================
-
-tapX are ethertap devices which provide an interface to the kernel's ethernet
-layer. Packets can be read from and written to the /dev/tapX character devices
-one at a time (same name as the interface that shows up in ifconfig).
-
-tunX are IP tunnel devices. These can be used to exchange IP packets with the
-kernel. You will get single packets for each read() and should write() packets
-one at a time to /dev/tunX.
-
-There are some special ioctls with the tun devices that allow you to have them
-prepend the address family of the packet when reading it from /dev/tunX. Using
-this mode the driver also expects you put this 4-byte address family field
-(network byte order) in front of the packets you write to /dev/tunX.
-
-Here are the ioctls to setup up address prepending mode (for convenience there
-also is a header called tun_ioctls.h in the source package that you can use)
-Set the int argument to one if you want to have AF prepending, use 0 if you want
-to switch it off.
-
-#define TUNSIFHEAD _IOW('t', 96, int)
-#define TUNGIFHEAD _IOR('t', 97, int)
-
-Prepending mode is off by default. Currently it is not recommended to switch the
-mode while packets are in flight on the device.
-
-The character devices are always visible in the filesystem as /dev/tunX and
-/dev/tapX. The number of available character devices is a compile time constant
-and is currently fixed to 16. Each character devices is associated with a
-network interface of the same name. The network interfaces are only created when
-the corresponding character device is opened by a program and will be removed
-when the character device is closed.
-
-The character devices currently provide a pretty minimal interface. Whole
-packets are read and written using a singe read/write call. File descriptors
-opened on the devices can also be select()ed and support O_NONBLOCK.
-Asynchronous i/o and some ioctls are currently unimplemented, but implementing
-them shouldn't be very hard. Do it yourself or contact me if you can't live
-without.
-
-There is another limitation imposed by the Darwin 8 kernel. It concerns the
-poll() system call; Darwin currently does *not* support that for (character)
-devices. Use select() instead.
-
-The interfaces can be configured using ifconfig, the tap devices also support
-setting the MAC address to be used. Both tun and tap should be ready for IPv6.
-Just setup addresses and routing as you would do with other interfaces.
-
-Please contact me if you find any bugs or have suggestions.
-
-Enjoy!
-
-Mattias
-<mattias.nissler@gmx.de>
-
-
-Uninstalling
-============
-
-The installer packages for OS X currently don't have support for uninstall as
-the installer doesn't provide it. Remove the following directories if you want
-to completely remove the files installed:
-
-/Library/Extensions/tap.kext
-/Library/Extensions/tun.kext
-/Library/StartupItems/tap
-/Library/StartupItems/tun
-
-Unload the the kernel extensions or reboot and you're done.
-
diff --git a/ext/tap-mac/tuntap/README.zerotier-build b/ext/tap-mac/tuntap/README.zerotier-build
deleted file mode 100644
index 550e0378..00000000
--- a/ext/tap-mac/tuntap/README.zerotier-build
+++ /dev/null
@@ -1,23 +0,0 @@
-Building the tap for both x86_64 and i386 requires an older version of the
-Xcode tools than what now ships for Mavericks (10.9). The newer version
-does not support creating i386 kernel images.
-
-At the moment this is done on an OSX 10.6 virtual image that is used for
-building. (It doesn't have to be done often.) Then the kext is signed on
-the regular build system. That's because images built on newer OSX don't
-seem to load on 10.6 but 10.6 built kexts seem fine on 10.9. Go figure.
-
-Older Xcode can also be found at:
-
-https://developer.apple.com/downloads
-
-It requires a bit of a dance to unpack the package and obtain an unpacked
-tree, but once it's there you can change the line in tap/Makefile and
-build for both architectures.
-
-This will go on until i386 is thoroughly legacy, at which point we'll
-probably start just supporting x86_64. But that might be a while. We want
-to support old Macs through their entire useful life.
-
-Since this build is irritating, a pre-built copy is packaged in ext/ and
-is installed by 'make install'. So users shouldn't have to build this.
diff --git a/ext/tap-mac/tuntap/src/lock.cc b/ext/tap-mac/tuntap/src/lock.cc
index 0da48be2..9c78783a 100644
--- a/ext/tap-mac/tuntap/src/lock.cc
+++ b/ext/tap-mac/tuntap/src/lock.cc
@@ -31,6 +31,8 @@
extern "C" {
+#include <kern/clock.h>
+
#include <sys/syslog.h>
#include <sys/proc.h>
@@ -120,10 +122,13 @@ tt_mutex::sleep(void *cond)
}
void
-tt_mutex::sleep(void *cond, uint64_t timeout)
+tt_mutex::sleep(void *cond, uint64_t nanoseconds)
{
- if (lck != NULL)
- lck_rw_sleep_deadline(lck, LCK_SLEEP_DEFAULT, cond, THREAD_INTERRUPTIBLE, timeout);
+ if (lck != NULL) {
+ uint64_t abstime;
+ nanoseconds_to_absolutetime(nanoseconds, &abstime);
+ lck_rw_sleep_deadline(lck, LCK_SLEEP_DEFAULT, cond, THREAD_INTERRUPTIBLE, abstime);
+ }
}
void
@@ -188,9 +193,9 @@ tt_gate::sleep(void* cond)
}
void
-tt_gate::sleep(void* cond, uint64_t timeout)
+tt_gate::sleep(void* cond, uint64_t nanoseconds)
{
- slock.sleep(cond, timeout);
+ slock.sleep(cond, nanoseconds);
}
void
diff --git a/ext/tap-mac/tuntap/src/tap/Makefile b/ext/tap-mac/tuntap/src/tap/Makefile
index ee1f5457..306a86d7 100644
--- a/ext/tap-mac/tuntap/src/tap/Makefile
+++ b/ext/tap-mac/tuntap/src/tap/Makefile
@@ -19,18 +19,18 @@ BUNDLE_SIGNATURE = ????
BUNDLE_PACKAGETYPE = KEXT
BUNDLE_VERSION = $(TAP_KEXT_VERSION)
-INCLUDE = -I.. -I/System/Library/Frameworks/Kernel.framework/Headers -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/Kernel.framework/Headers
-CFLAGS = -Wall -mkernel -force_cpusubtype_ALL \
- -fno-builtin -fno-stack-protector -arch i386 -arch x86_64 \
- -DKERNEL -D__APPLE__ -DKERNEL_PRIVATE -DTUNTAP_VERSION=\"$(TUNTAP_VERSION)\" \
+INCLUDE = -I.. -I/System/Library/Frameworks/Kernel.framework/Headers
+CFLAGS = -Wall -Werror -mkernel -force_cpusubtype_ALL \
+ -nostdinc -fno-builtin -fno-stack-protector -msoft-float -fno-common \
+ -arch x86_64 \
+ -DKERNEL -DAPPLE -DKERNEL_PRIVATE -DTUNTAP_VERSION=\"$(TUNTAP_VERSION)\" \
-DTAP_KEXT_VERSION=\"$(TAP_KEXT_VERSION)\"
CCFLAGS = $(CFLAGS)
-LDFLAGS = -Wall -mkernel -nostdlib -r -lcc_kext -arch i386 -arch x86_64 -Xlinker -kext
+LDFLAGS = -Wall -Werror -arch x86_64 -Xlinker -kext -nostdlib -lkmodc++ -lkmod -lcc_kext
-#CCP = g++
-#CC = gcc
-CCP = ../../../../llvm-g++-Xcode4.6.2/bin/llvm-g++
-CC = ../../../../llvm-g++-Xcode4.6.2/bin/llvm-gcc
+CCP = clang -x c++
+CC = clang -x c
+LD = clang
all: $(KMOD_BIN) bundle
@@ -40,7 +40,7 @@ all: $(KMOD_BIN) bundle
$(CCP) $(CCFLAGS) $(INCLUDE) -c $< -o $@
$(KMOD_BIN): $(OBJS)
- $(CCP) $(LDFLAGS) -o $(KMOD_BIN) $(OBJS)
+ $(LD) $(LDFLAGS) -o $(KMOD_BIN) $(OBJS)
bundle: $(KMOD_BIN)
rm -rf $(BUNDLE_DIR)/$(BUNDLE_NAME)
diff --git a/ext/tap-mac/tuntap/src/tap/tap.cc b/ext/tap-mac/tuntap/src/tap/tap.cc
index 149f1e71..b348a85e 100644
--- a/ext/tap-mac/tuntap/src/tap/tap.cc
+++ b/ext/tap-mac/tuntap/src/tap/tap.cc
@@ -38,6 +38,8 @@ extern "C" {
#include <sys/random.h>
#include <sys/kern_event.h>
+#include <mach/thread_policy.h>
+
#include <net/if_types.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
@@ -89,10 +91,25 @@ struct ifmediareq32 {
#define SIOCGIFMEDIA32 _IOWR('i', 56, struct ifmediareq32) /* get net media */
#define SIOCGIFMEDIA64 _IOWR('i', 56, struct ifmediareq64) /* get net media (64-bit) */
+/* thread_policy_set is exported in Mach.kext, but commented in mach/thread_policy.h in the
+ * Kernel.Framework headers (why?). Add a local declaration to work around that.
+ */
+extern "C" {
+kern_return_t thread_policy_set(
+ thread_t thread,
+ thread_policy_flavor_t flavor,
+ thread_policy_t policy_info,
+ mach_msg_type_number_t count);
+}
static unsigned char ETHER_BROADCAST_ADDR[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
/* members */
+tap_interface::tap_interface() {
+ bzero(attached_protos, sizeof(attached_protos));
+ input_thread = THREAD_NULL;
+}
+
bool
tap_interface::initialize(unsigned short major, unsigned short unit)
{
@@ -166,6 +183,30 @@ tap_interface::initialize_interface()
*/
bpfattach(ifp, DLT_EN10MB, ifnet_hdrlen(ifp));
+ /* Inject an empty packet to trigger the input thread calling demux(), which will unblock
+ * thread_sync_lock. This is part of a hack to avoid a kernel crash on re-attaching
+ * interfaces, see comment in shutdown_interface for more information.
+ */
+ mbuf_t empty_mbuf;
+ mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &empty_mbuf);
+ if (empty_mbuf != NULL) {
+ mbuf_pkthdr_setrcvif(empty_mbuf, ifp);
+ mbuf_pkthdr_setlen(empty_mbuf, 0);
+ mbuf_pkthdr_setheader(empty_mbuf, mbuf_data(empty_mbuf));
+ mbuf_set_csum_performed(empty_mbuf, 0, 0);
+ if (ifnet_input(ifp, empty_mbuf, NULL) == 0) {
+ auto_lock l(&thread_sync_lock);
+ for (int i = 0; i < 100 && input_thread == THREAD_NULL; ++i) {
+ dprintf("input thread not found, waiting...\n");
+ thread_sync_lock.sleep(&input_thread, 10000000);
+ }
+ } else {
+ mbuf_freem(empty_mbuf);
+ }
+ }
+ if (input_thread == THREAD_NULL)
+ dprintf("Failed to determine input thread!\n");
+
return 0;
}
@@ -186,6 +227,36 @@ tap_interface::shutdown_interface()
cleanup_interface();
unregister_interface();
+
+ /* There's a race condition in the kernel that may cause crashes when quickly re-attaching
+ * interfaces. The crash happens when the interface gets re-attached before the input thread
+ * for the interface managed to terminate, in which case an assert on the input_waiting flag
+ * to be clear triggers in ifnet_attach. The bug is really that there's no synchronization
+ * for terminating the input thread. To work around this, the following code does add the
+ * missing synchronization to wait for the input thread to terminate. Of course, threading
+ * primitives available to kexts are few, and I'm not aware of a way to wait for a thread to
+ * terminate. Hence, the code calls thread_policy_set (passing bogus parameters) in a loop,
+ * until it returns KERN_TERMINATED. Since this is all rather fragile, there's an upper
+ * limit on the loop iteratations we're willing to make, so this terminates eventually even
+ * if things change on the kernel side eventually.
+ */
+ if (input_thread != THREAD_NULL) {
+ dprintf("Waiting for input thread...\n");
+ kern_return_t result = 0;
+ for (int i = 0; i < 100; ++i) {
+ result = thread_policy_set(input_thread, -1, NULL, 0);
+ dprintf("thread_policy_set result: %d\n", result);
+ if (result == KERN_TERMINATED) {
+ dprintf("Input thread terminated.\n");
+ thread_deallocate(input_thread);
+ input_thread = THREAD_NULL;
+ break;
+ }
+
+ auto_lock l(&thread_sync_lock);
+ thread_sync_lock.sleep(&input_thread, 10000000);
+ }
+ }
}
errno_t
@@ -263,6 +334,16 @@ tap_interface::if_demux(mbuf_t m, char *header, protocol_family_t *proto)
dprintf("tap: if_demux\n");
+ /* Make note of what input thread this interface is running on. This is part of a hack to
+ * avoid a crash on re-attaching interfaces, see comment in shutdown_interface for details.
+ */
+ if (input_thread == THREAD_NULL) {
+ auto_lock l(&thread_sync_lock);
+ input_thread = current_thread();
+ thread_reference(input_thread);
+ thread_sync_lock.wakeup(&input_thread);
+ }
+
/* size check */
if (mbuf_len(m) < sizeof(struct ether_header))
return ENOENT;
diff --git a/ext/tap-mac/tuntap/src/tap/tap.h b/ext/tap-mac/tuntap/src/tap/tap.h
index 72339a95..a5164d4a 100644
--- a/ext/tap-mac/tuntap/src/tap/tap.h
+++ b/ext/tap-mac/tuntap/src/tap/tap.h
@@ -30,12 +30,15 @@
#include "tuntap.h"
-#define TAP_FAMILY_NAME ((char *) "zt")
+extern "C" {
-#define TAP_IF_COUNT 32 /* max number of tap interfaces */
+#include <kern/thread.h>
-#define TAP_MTU 2800
+}
+#define TAP_FAMILY_NAME ((char *) "zt")
+#define TAP_IF_COUNT 32 /* max number of tap interfaces */
+#define TAP_MTU 2800
#define TAP_LLADDR tap_lladdr
/* the mac address of our interfaces. note that the last byte will be replaced by the unit number */
@@ -52,6 +55,8 @@ class tap_manager : public tuntap_manager {
/* the tap network interface */
class tap_interface : public tuntap_interface {
+ public:
+ tap_interface();
protected:
/* maximum number of protocols that can be attached */
@@ -67,6 +72,9 @@ class tap_interface : public tuntap_interface {
protocol_family_t proto;
} attached_protos[MAX_ATTACHED_PROTOS];
+ /* The input thread for the network interface. */
+ thread_t input_thread;
+
/* initializes the interface */
virtual bool initialize(unsigned short major, unsigned short unit);
diff --git a/ext/tap-mac/tuntap/src/tuntap.cc b/ext/tap-mac/tuntap/src/tuntap.cc
index 7fdbb795..d0f89018 100644
--- a/ext/tap-mac/tuntap/src/tuntap.cc
+++ b/ext/tap-mac/tuntap/src/tuntap.cc
@@ -384,10 +384,10 @@ tuntap_interface::unregister_interface()
dprintf("interface detaching\n");
/* Wait until the interface has completely been detached. */
- detach_lock.lock();
+ thread_sync_lock.lock();
while (!interface_detached)
- detach_lock.sleep(&interface_detached);
- detach_lock.unlock();
+ thread_sync_lock.sleep(&interface_detached);
+ thread_sync_lock.unlock();
dprintf("interface detached\n");
@@ -642,15 +642,14 @@ tuntap_interface::cdev_write(uio_t uio, int ioflag)
unsigned int mlen = mbuf_maxlen(first);
unsigned int chunk_len;
unsigned int copied = 0;
+ unsigned int max_data_len = ifnet_mtu(ifp) + ifnet_hdrlen(ifp);
int error;
/* stuff the data into the mbuf(s) */
mb = first;
while (uio_resid(uio) > 0) {
/* copy a chunk. enforce mtu (don't know if this is correct behaviour) */
- // ... evidently not :) -- Adam Ierymenko <adam.ierymenko@zerotier.com>
- //chunk_len = min(ifnet_mtu(ifp), min(uio_resid(uio), mlen));
- chunk_len = min(uio_resid(uio),mlen);
+ chunk_len = min(max_data_len - copied, min(uio_resid(uio), mlen));
error = uiomove((caddr_t) mbuf_data(mb), chunk_len, uio);
if (error) {
log(LOG_ERR, "tuntap: could not copy data from userspace: %d\n", error);
@@ -666,9 +665,7 @@ tuntap_interface::cdev_write(uio_t uio, int ioflag)
copied += chunk_len;
/* if done, break the loop */
- //if (uio_resid(uio) <= 0 || copied >= ifnet_mtu(ifp))
- // break;
- if (uio_resid(uio) <= 0)
+ if (uio_resid(uio) <= 0 || copied >= max_data_len)
break;
/* allocate a new mbuf if the current is filled */
@@ -956,10 +953,10 @@ tuntap_interface::if_detached()
dprintf("tuntap: if_detached\n");
/* wake unregister_interface() */
- detach_lock.lock();
+ thread_sync_lock.lock();
interface_detached = true;
- detach_lock.wakeup(&interface_detached);
- detach_lock.unlock();
+ thread_sync_lock.wakeup(&interface_detached);
+ thread_sync_lock.unlock();
dprintf("if_detached done\n");
}
diff --git a/ext/tap-mac/tuntap/src/tuntap.h b/ext/tap-mac/tuntap/src/tuntap.h
index f10d4a06..d5f398d0 100644
--- a/ext/tap-mac/tuntap/src/tuntap.h
+++ b/ext/tap-mac/tuntap/src/tuntap.h
@@ -197,7 +197,7 @@ class tuntap_interface {
/* synchronization */
tt_mutex lock;
tt_mutex bpf_lock;
- tt_mutex detach_lock;
+ tt_mutex thread_sync_lock;
/* the interface structure registered */
ifnet_t ifp;
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index 341bb767..377af63f 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -129,6 +129,21 @@ extern "C" {
#define ZT_CIRCUIT_TEST_MAX_HOP_BREADTH 256
/**
+ * Maximum number of cluster members (and max member ID plus one)
+ */
+#define ZT_CLUSTER_MAX_MEMBERS 128
+
+/**
+ * Maximum number of physical ZeroTier addresses a cluster member can report
+ */
+#define ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES 16
+
+/**
+ * Maximum allowed cluster message length in bytes
+ */
+#define ZT_CLUSTER_MAX_MESSAGE_LENGTH (1500 - 48)
+
+/**
* A null/empty sockaddr (all zero) to signify an unspecified socket address
*/
extern const struct sockaddr_storage ZT_SOCKADDR_NULL;
@@ -174,7 +189,17 @@ enum ZT_ResultCode
/**
* Network ID not valid
*/
- ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000
+ ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000,
+
+ /**
+ * The requested operation is not supported on this version or build
+ */
+ ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001,
+
+ /**
+ * The requestion operation was given a bad parameter or was called in an invalid state
+ */
+ ZT_RESULT_ERROR_BAD_PARAMETER = 1002
};
/**
@@ -256,38 +281,13 @@ enum ZT_Event
ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION = 4,
/**
- * A more recent version was observed on the network
- *
- * Right now this is only triggered if a hub or rootserver reports a
- * more recent version, and only once. It can be used to trigger a
- * software update check.
- *
- * Meta-data: unsigned int[3], more recent version number
- */
- ZT_EVENT_SAW_MORE_RECENT_VERSION = 5,
-
- /**
- * A packet failed authentication
- *
- * Meta-data: struct sockaddr_storage containing origin address of packet
- */
- ZT_EVENT_AUTHENTICATION_FAILURE = 6,
-
- /**
- * A received packet was not valid
- *
- * Meta-data: struct sockaddr_storage containing origin address of packet
- */
- ZT_EVENT_INVALID_PACKET = 7,
-
- /**
* Trace (debugging) message
*
* These events are only generated if this is a TRACE-enabled build.
*
* Meta-data: C string, TRACE message
*/
- ZT_EVENT_TRACE = 8
+ ZT_EVENT_TRACE = 5
};
/**
@@ -301,6 +301,16 @@ typedef struct
uint64_t address;
/**
+ * Current world ID
+ */
+ uint64_t worldId;
+
+ /**
+ * Current world revision/timestamp
+ */
+ uint64_t worldTimestamp;
+
+ /**
* Public identity in string-serialized form (safe to send to others)
*
* This pointer will remain valid as long as the node exists.
@@ -415,6 +425,59 @@ enum ZT_VirtualNetworkConfigOperation
};
/**
+ * What trust hierarchy role does this peer have?
+ */
+enum ZT_PeerRole {
+ ZT_PEER_ROLE_LEAF = 0, // ordinary node
+ ZT_PEER_ROLE_RELAY = 1, // relay node
+ ZT_PEER_ROLE_ROOT = 2 // root server
+};
+
+/**
+ * Vendor ID
+ */
+enum ZT_Vendor {
+ ZT_VENDOR_UNSPECIFIED = 0,
+ ZT_VENDOR_ZEROTIER = 1
+};
+
+/**
+ * Platform type
+ */
+enum ZT_Platform {
+ ZT_PLATFORM_UNSPECIFIED = 0,
+ ZT_PLATFORM_LINUX = 1,
+ ZT_PLATFORM_WINDOWS = 2,
+ ZT_PLATFORM_MACOS = 3,
+ ZT_PLATFORM_ANDROID = 4,
+ ZT_PLATFORM_IOS = 5,
+ ZT_PLATFORM_SOLARIS_SMARTOS = 6,
+ ZT_PLATFORM_FREEBSD = 7,
+ ZT_PLATFORM_NETBSD = 8,
+ ZT_PLATFORM_OPENBSD = 9,
+ ZT_PLATFORM_RISCOS = 10,
+ ZT_PLATFORM_VXWORKS = 11,
+ ZT_PLATFORM_FREERTOS = 12,
+ ZT_PLATFORM_SYSBIOS = 13,
+ ZT_PLATFORM_HURD = 14
+};
+
+/**
+ * Architecture type
+ */
+enum ZT_Architecture {
+ ZT_ARCHITECTURE_UNSPECIFIED = 0,
+ ZT_ARCHITECTURE_X86 = 1,
+ ZT_ARCHITECTURE_X64 = 2,
+ ZT_ARCHITECTURE_ARM32 = 3,
+ ZT_ARCHITECTURE_ARM64 = 4,
+ ZT_ARCHITECTURE_MIPS32 = 5,
+ ZT_ARCHITECTURE_MIPS64 = 6,
+ ZT_ARCHITECTURE_POWER32 = 7,
+ ZT_ARCHITECTURE_POWER64 = 8
+};
+
+/**
* Virtual network configuration
*/
typedef struct
@@ -546,11 +609,6 @@ typedef struct
uint64_t lastReceive;
/**
- * Is path fixed? (i.e. not learned, static)
- */
- int fixed;
-
- /**
* Is path active?
*/
int active;
@@ -562,15 +620,6 @@ typedef struct
} ZT_PeerPhysicalPath;
/**
- * What trust hierarchy role does this peer have?
- */
-enum ZT_PeerRole {
- ZT_PEER_ROLE_LEAF = 0, // ordinary node
- ZT_PEER_ROLE_RELAY = 1, // relay node
- ZT_PEER_ROLE_ROOT = 2 // root server
-};
-
-/**
* Peer status result buffer
*/
typedef struct
@@ -636,59 +685,6 @@ typedef struct
} ZT_PeerList;
/**
- * Local interface trust levels
- */
-typedef enum {
- ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL = 0,
- ZT_LOCAL_INTERFACE_ADDRESS_TRUST_PRIVACY = 10,
- ZT_LOCAL_INTERFACE_ADDRESS_TRUST_ULTIMATE = 20
-} ZT_LocalInterfaceAddressTrust;
-
-/**
- * Vendor ID
- */
-typedef enum {
- ZT_VENDOR_UNSPECIFIED = 0,
- ZT_VENDOR_ZEROTIER = 1
-} ZT_Vendor;
-
-/**
- * Platform type
- */
-typedef enum {
- ZT_PLATFORM_UNSPECIFIED = 0,
- ZT_PLATFORM_LINUX = 1,
- ZT_PLATFORM_WINDOWS = 2,
- ZT_PLATFORM_MACOS = 3,
- ZT_PLATFORM_ANDROID = 4,
- ZT_PLATFORM_IOS = 5,
- ZT_PLATFORM_SOLARIS_SMARTOS = 6,
- ZT_PLATFORM_FREEBSD = 7,
- ZT_PLATFORM_NETBSD = 8,
- ZT_PLATFORM_OPENBSD = 9,
- ZT_PLATFORM_RISCOS = 10,
- ZT_PLATFORM_VXWORKS = 11,
- ZT_PLATFORM_FREERTOS = 12,
- ZT_PLATFORM_SYSBIOS = 13,
- ZT_PLATFORM_HURD = 14
-} ZT_Platform;
-
-/**
- * Architecture type
- */
-typedef enum {
- ZT_ARCHITECTURE_UNSPECIFIED = 0,
- ZT_ARCHITECTURE_X86 = 1,
- ZT_ARCHITECTURE_X64 = 2,
- ZT_ARCHITECTURE_ARM32 = 3,
- ZT_ARCHITECTURE_ARM64 = 4,
- ZT_ARCHITECTURE_MIPS32 = 5,
- ZT_ARCHITECTURE_MIPS64 = 6,
- ZT_ARCHITECTURE_POWER32 = 7,
- ZT_ARCHITECTURE_POWER64 = 8
-} ZT_Architecture;
-
-/**
* ZeroTier circuit test configuration and path
*/
typedef struct {
@@ -758,9 +754,14 @@ typedef struct {
*/
typedef struct {
/**
- * Sender of report
+ * Sender of report (current hop)
*/
- uint64_t address;
+ uint64_t current;
+
+ /**
+ * Previous hop
+ */
+ uint64_t upstream;
/**
* 64-bit test ID
@@ -800,7 +801,7 @@ typedef struct {
/**
* Remote device vendor ID
*/
- ZT_Vendor vendor;
+ enum ZT_Vendor vendor;
/**
* Remote device protocol compliance version
@@ -825,12 +826,12 @@ typedef struct {
/**
* Platform / OS
*/
- ZT_Platform platform;
+ enum ZT_Platform platform;
/**
* System architecture
*/
- ZT_Architecture architecture;
+ enum ZT_Architecture architecture;
/**
* Local device address on which packet was received by reporting device
@@ -875,6 +876,78 @@ typedef struct {
} ZT_CircuitTestReport;
/**
+ * A cluster member's status
+ */
+typedef struct {
+ /**
+ * This cluster member's ID (from 0 to 1-ZT_CLUSTER_MAX_MEMBERS)
+ */
+ unsigned int id;
+
+ /**
+ * Number of milliseconds since last 'alive' heartbeat message received via cluster backplane address
+ */
+ unsigned int msSinceLastHeartbeat;
+
+ /**
+ * Non-zero if cluster member is alive
+ */
+ int alive;
+
+ /**
+ * X, Y, and Z coordinates of this member (if specified, otherwise zero)
+ *
+ * What these mean depends on the location scheme being used for
+ * location-aware clustering. At present this is GeoIP and these
+ * will be the X, Y, and Z coordinates of the location on a spherical
+ * approximation of Earth where Earth's core is the origin (in km).
+ * They don't have to be perfect and need only be comparable with others
+ * to find shortest path via the standard vector distance formula.
+ */
+ int x,y,z;
+
+ /**
+ * Cluster member's last reported load
+ */
+ uint64_t load;
+
+ /**
+ * Number of peers
+ */
+ uint64_t peers;
+
+ /**
+ * Physical ZeroTier endpoints for this member (where peers are sent when directed here)
+ */
+ struct sockaddr_storage zeroTierPhysicalEndpoints[ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES];
+
+ /**
+ * Number of physical ZeroTier endpoints this member is announcing
+ */
+ unsigned int numZeroTierPhysicalEndpoints;
+} ZT_ClusterMemberStatus;
+
+/**
+ * ZeroTier cluster status
+ */
+typedef struct {
+ /**
+ * My cluster member ID (a record for 'self' is included in member[])
+ */
+ unsigned int myId;
+
+ /**
+ * Number of cluster members
+ */
+ unsigned int clusterSize;
+
+ /**
+ * Cluster member statuses
+ */
+ ZT_ClusterMemberStatus members[ZT_CLUSTER_MAX_MEMBERS];
+} ZT_ClusterStatus;
+
+/**
* An instance of a ZeroTier One node (opaque)
*/
typedef void ZT_Node;
@@ -1007,6 +1080,7 @@ typedef int (*ZT_DataStorePutFunction)(
* (4) Remote address
* (5) Packet data
* (6) Packet length
+ * (7) Desired IP TTL or 0 to use default
*
* If there is only one local interface it is safe to ignore the local
* interface address. Otherwise if running with multiple interfaces, the
@@ -1014,17 +1088,22 @@ typedef int (*ZT_DataStorePutFunction)(
* the ss_family field is zero (NULL address), a random or preferred
* default interface should be used.
*
+ * If TTL is nonzero, packets should have their IP TTL value set to this
+ * value if possible. If this is not possible it is acceptable to ignore
+ * this value and send anyway with normal or default TTL.
+ *
* The function must return zero on success and may return any error code
* on failure. Note that success does not (of course) guarantee packet
* delivery. It only means that the packet appears to have been sent.
*/
typedef int (*ZT_WirePacketSendFunction)(
- ZT_Node *, /* Node */
+ ZT_Node *, /* Node */
void *, /* User ptr */
const struct sockaddr_storage *, /* Local address */
const struct sockaddr_storage *, /* Remote address */
const void *, /* Packet data */
- unsigned int); /* Packet length */
+ unsigned int, /* Packet length */
+ unsigned int); /* TTL or 0 to use default */
/****************************************************************************/
/* C Node API */
@@ -1043,7 +1122,6 @@ typedef int (*ZT_WirePacketSendFunction)(
* @param dataStorePutFunction Function called to put objects in persistent storage
* @param virtualNetworkConfigFunction Function to be called when virtual LANs are created, deleted, or their config parameters change
* @param eventCallback Function to receive status updates and non-fatal error notices
- * @param overrideRootTopology Alternative root server topology or NULL for default (mostly for test/debug use)
* @return OK (0) or error code if a fatal error condition has occurred
*/
enum ZT_ResultCode ZT_Node_new(
@@ -1055,8 +1133,7 @@ enum ZT_ResultCode ZT_Node_new(
ZT_WirePacketSendFunction wirePacketSendFunction,
ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
- ZT_EventCallback eventCallback,
- const char *overrideRootTopology);
+ ZT_EventCallback eventCallback);
/**
* Delete a node and free all resources it consumes
@@ -1257,11 +1334,6 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr);
/**
* Add a local interface address
*
- * Local interface addresses may be added if you want remote peers
- * with whom you have a trust relatinship (e.g. common network membership)
- * to receive information about these endpoints as potential endpoints for
- * direct communication.
- *
* Take care that these are never ZeroTier interface addresses, otherwise
* strange things might happen or they simply won't work.
*
@@ -1276,11 +1348,9 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr);
* reject bad, empty, and unusable addresses.
*
* @param addr Local interface address
- * @param metric Local interface metric
- * @param trust How much do you trust the local network under this interface?
* @return Boolean: non-zero if address was accepted and added
*/
-int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust);
+int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr);
/**
* Clear local interface addresses
@@ -1321,7 +1391,7 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance);
* @param reportCallback Function to call each time a report is received
* @return OK or error if, for example, test is too big for a packet or support isn't compiled in
*/
-ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *));
+enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *));
/**
* Stop listening for results to a given circuit test
@@ -1338,6 +1408,137 @@ ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (
void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test);
/**
+ * Initialize cluster operation
+ *
+ * This initializes the internal structures and state for cluster operation.
+ * It takes two function pointers. The first is to a function that can be
+ * used to send data to cluster peers (mechanism is not defined by Node),
+ * and the second is to a function that can be used to get the location of
+ * a physical address in X,Y,Z coordinate space (e.g. as cartesian coordinates
+ * projected from the center of the Earth).
+ *
+ * Send function takes an arbitrary pointer followed by the cluster member ID
+ * to send data to, a pointer to the data, and the length of the data. The
+ * maximum message length is ZT_CLUSTER_MAX_MESSAGE_LENGTH (65535). Messages
+ * must be delivered whole and may be dropped or transposed, though high
+ * failure rates are undesirable and can cause problems. Validity checking or
+ * CRC is also not required since the Node validates the authenticity of
+ * cluster messages using cryptogrphic methods and will silently drop invalid
+ * messages.
+ *
+ * Address to location function is optional and if NULL geo-handoff is not
+ * enabled (in this case x, y, and z in clusterInit are also unused). It
+ * takes an arbitrary pointer followed by a physical address and three result
+ * parameters for x, y, and z. It returns zero on failure or nonzero if these
+ * three coordinates have been set. Coordinate space is arbitrary and can be
+ * e.g. coordinates on Earth relative to Earth's center. These can be obtained
+ * from latitutde and longitude with versions of the Haversine formula.
+ *
+ * See: http://stackoverflow.com/questions/1185408/converting-from-longitude-latitude-to-cartesian-coordinates
+ *
+ * Neither the send nor the address to location function should block. If the
+ * address to location function does not have a location for an address, it
+ * should return zero and then look up the address for future use since it
+ * will be called again in (typically) 1-3 minutes.
+ *
+ * Note that both functions can be called from any thread from which the
+ * various Node functions are called, and so must be thread safe if multiple
+ * threads are being used.
+ *
+ * @param node Node instance
+ * @param myId My cluster member ID (less than or equal to ZT_CLUSTER_MAX_MEMBERS)
+ * @param zeroTierPhysicalEndpoints Preferred physical address(es) for ZeroTier clients to contact this cluster member (for peer redirect)
+ * @param numZeroTierPhysicalEndpoints Number of physical endpoints in zeroTierPhysicalEndpoints[] (max allowed: 255)
+ * @param x My cluster member's X location
+ * @param y My cluster member's Y location
+ * @param z My cluster member's Z location
+ * @param sendFunction Function to be called to send data to other cluster members
+ * @param sendFunctionArg First argument to sendFunction()
+ * @param addressToLocationFunction Function to be called to get the location of a physical address or NULL to disable geo-handoff
+ * @param addressToLocationFunctionArg First argument to addressToLocationFunction()
+ * @return OK or UNSUPPORTED_OPERATION if this Node was not built with cluster support
+ */
+enum ZT_ResultCode ZT_Node_clusterInit(
+ ZT_Node *node,
+ unsigned int myId,
+ const struct sockaddr_storage *zeroTierPhysicalEndpoints,
+ unsigned int numZeroTierPhysicalEndpoints,
+ int x,
+ int y,
+ int z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg);
+
+/**
+ * Add a member to this cluster
+ *
+ * Calling this without having called clusterInit() will do nothing.
+ *
+ * @param node Node instance
+ * @param memberId Member ID (must be less than or equal to ZT_CLUSTER_MAX_MEMBERS)
+ * @return OK or error if clustering is disabled, ID invalid, etc.
+ */
+enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId);
+
+/**
+ * Remove a member from this cluster
+ *
+ * Calling this without having called clusterInit() will do nothing.
+ *
+ * @param node Node instance
+ * @param memberId Member ID to remove (nothing happens if not present)
+ */
+void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId);
+
+/**
+ * Handle an incoming cluster state message
+ *
+ * The message itself contains cluster member IDs, and invalid or badly
+ * addressed messages will be silently discarded.
+ *
+ * Calling this without having called clusterInit() will do nothing.
+ *
+ * @param node Node instance
+ * @param msg Cluster message
+ * @param len Length of cluster message
+ */
+void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len);
+
+/**
+ * Get the current status of the cluster from this node's point of view
+ *
+ * Calling this without clusterInit() or without cluster support will just
+ * zero out the structure and show a cluster size of zero.
+ *
+ * @param node Node instance
+ * @param cs Cluster status structure to fill with data
+ */
+void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs);
+
+/**
+ * Do things in the background until Node dies
+ *
+ * This function can be called from one or more background threads to process
+ * certain tasks in the background to improve foreground performance. It will
+ * not return until the Node is shut down. If threading is not enabled in
+ * this build it will return immediately and will do nothing.
+ *
+ * This is completely optional. If this is never called, all processing is
+ * done in the foreground in the various processXXXX() methods.
+ *
+ * This does NOT replace or eliminate the need to call the normal
+ * processBackgroundTasks() function in your main loop. This mechanism is
+ * used to offload the processing of expensive mssages onto background
+ * handler threads to prevent foreground performance degradation under
+ * high load.
+ *
+ * @param node Node instance
+ */
+void ZT_Node_backgroundThreadMain(ZT_Node *node);
+
+/**
* Get ZeroTier One version
*
* @param major Result: major version
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index 25e32638..008b747b 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -59,6 +59,7 @@ set(src_files
set(include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/../include/
+ ${CMAKE_CURRENT_SOURCE_DIR}/../node/
${Java_INCLUDE_DIRS})
if(WIN32)
diff --git a/java/build.xml b/java/build.xml
index e24a0e13..4604ad66 100644
--- a/java/build.xml
+++ b/java/build.xml
@@ -1,4 +1,4 @@
-<project default="build" name="ZeroTierOneSDK" basedir=".">
+<project default="build_jar" name="ZeroTierOneSDK" basedir=".">
<property environment="env"/>
<condition property="isWindows">
@@ -9,7 +9,7 @@
<os family="mac"/>
</condition>
- <target name="clean">
+ <target name="clean_ant">
<delete dir="bin" failonerror="false"/>
<delete dir="classes" failonerror="false"/>
<delete dir="build_win32" failonerror="false"/>
@@ -24,6 +24,10 @@
<echo message="os.arch = ${os.arch}"/>
<echo message="ant.java.version = ${ant.java.version}"/>
<echo message="java.version = ${java.version}"/>
+ <echo message="ndk.loc = ${env.NDK_BUILD_LOC}"/>
+ <echo message="sdk.loc = ${env.ANDROID_PLATFORM}"/>
+ <echo message="user.dir = ${user.dir}"/>
+ <echo message="zt1.dir = ${env.ZT}"/>
<mkdir dir="bin"/>
<mkdir dir="classes"/>
<javac srcdir="src"
@@ -36,20 +40,30 @@
<target name="build_android">
<exec dir="jni" executable="${env.NDK_BUILD_LOC}" failonerror="true">
- <arg value="ZT1=${user.dir}/../"/>
+ <arg value="ZT1=${env.ZT}"/>
<arg value="V=1"/>
+ <!-- <arg value="NDK_DEBUG=1"/> -->
</exec>
- <copy file="libs/armeabi/libZeroTierOneJNI.so"
- tofile="${user.dir}/classes/lib/armeabi/libZeroTierOneJNI.so"
- overwrite="true"/>
<copy file="libs/arm64-v8a/libZeroTierOneJNI.so"
- tofile="${user.dir}/classes/lib/arm64-v8a/libZeroTierOneJNI.so"
+ tofile="classes/lib/arm64-v8a/libZeroTierOneJNI.so"
+ overwrite="true"/>
+ <copy file="libs/armeabi/libZeroTierOneJNI.so"
+ tofile="classes/lib/armeabi/libZeroTierOneJNI.so"
overwrite="true"/>
<copy file="libs/armeabi-v7a/libZeroTierOneJNI.so"
- tofile="${user.dir}/classes/lib/armeabi-v7a/libZeroTierOneJNI.so"
+ tofile="classes/lib/armeabi-v7a/libZeroTierOneJNI.so"
+ overwrite="true"/>
+ <copy file="libs/mips/libZeroTierOneJNI.so"
+ tofile="classes/lib/mips/libZeroTierOneJNI.so"
+ overwrite="true"/>
+ <copy file="libs/mips64/libZeroTierOneJNI.so"
+ tofile="classes/lib/mips64/libZeroTierOne.so"
overwrite="true"/>
<copy file="libs/x86/libZeroTierOneJNI.so"
- tofile="${user.dir}/classes/lib/x86/libZeroTierOneJNI.so"
+ tofile="classes/lib/x86/libZeroTierOneJNI.so"
+ overwrite="true"/>
+ <copy file="libs/x86_64/libZeroTierOneJNI.so"
+ tofile="classes/lib/x86_64/libZeroTierOneJNI.so"
overwrite="true"/>
</target>
@@ -91,7 +105,7 @@
overwrite="true"/>
</target>
- <target name="build" depends="build_java,build_android,windows,mac">
+ <target name="build_jar" depends="build_java,build_android,windows,mac">
<jar destfile="bin/ZeroTierOneSDK.jar" basedir="classes"/>
</target>
@@ -101,23 +115,4 @@
<javadoc sourcepath="src/"
destdir="doc/"/>
</target>
-
-<!-- <target name="android" depends="build">
- <echo message="OS is Android, installing..."/>
- <copy file="libs/armeabi/libZeroTierOneJNI.so"
- tofile="${aproj_loc}/libs/armeabi/libZeroTierOneJNI.so"
- overwrite="true"/>
- <copy file="libs/arm64-v8a/libZeroTierOneJNI.so"
- tofile="${aproj_loc}/libs/arm64-v8a/libZeroTierOneJNI.so"
- overwrite="true"/>
- <copy file="libs/armeabi-v7a/libZeroTierOneJNI.so"
- tofile="${aproj_loc}/libs/armeabi-v7a/libZeroTierOneJNI.so"
- overwrite="true"/>
- <copy file="libs/x86/libZeroTierOneJNI.so"
- tofile="${aproj_loc}/libs/x86/libZeroTierOneJNI.so"
- overwrite="true"/>
- <copy file="bin/ZeroTierOneSDK.jar"
- tofile="${aproj_loc}/libs/ZeroTierOneSDK.jar"
- overwrite="true"/>
- </target> -->
</project> \ No newline at end of file
diff --git a/java/jni/Android.mk b/java/jni/Android.mk
index 4dd4a57a..5c2f1c79 100644
--- a/java/jni/Android.mk
+++ b/java/jni/Android.mk
@@ -4,7 +4,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE := ZeroTierOneJNI
LOCAL_C_INCLUDES := $(ZT1)/include
+LOCAL_C_INCLUDES += $(ZT1)/node
LOCAL_LDLIBS := -llog
+# LOCAL_CFLAGS := -g
# ZeroTierOne SDK source files
LOCAL_SRC_FILES := \
@@ -13,7 +15,7 @@ LOCAL_SRC_FILES := \
$(ZT1)/ext/http-parser/http_parser.c \
$(ZT1)/node/C25519.cpp \
$(ZT1)/node/CertificateOfMembership.cpp \
- $(ZT1)/node/Defaults.cpp \
+ $(ZT1)/node/DeferredPackets.cpp \
$(ZT1)/node/Dictionary.cpp \
$(ZT1)/node/Identity.cpp \
$(ZT1)/node/IncomingPacket.cpp \
@@ -24,6 +26,7 @@ LOCAL_SRC_FILES := \
$(ZT1)/node/Node.cpp \
$(ZT1)/node/OutboundMulticast.cpp \
$(ZT1)/node/Packet.cpp \
+ $(ZT1)/node/Path.cpp \
$(ZT1)/node/Peer.cpp \
$(ZT1)/node/Poly1305.cpp \
$(ZT1)/node/Salsa20.cpp \
@@ -39,6 +42,6 @@ LOCAL_SRC_FILES := \
LOCAL_SRC_FILES += \
com_zerotierone_sdk_Node.cpp \
ZT_jniutils.cpp \
- ZT_jnicache.cpp
+ ZT_jnilookup.cpp
include $(BUILD_SHARED_LIBRARY) \ No newline at end of file
diff --git a/java/jni/Application.mk b/java/jni/Application.mk
index 3118ec2e..608e94c0 100644
--- a/java/jni/Application.mk
+++ b/java/jni/Application.mk
@@ -1,4 +1,5 @@
-APP_ABI := armeabi armeabi-v7a arm64-v8a x86
-APP_STL := gnustl_static
-APP_CPPFLAGS += -Wall -fPIE -fstack-protector -fexceptions -DZT_TRACE
-
+NDK_TOOLCHAIN_VERSION := clang
+APP_STL := c++_static
+APP_CPPFLAGS := -O3 -fPIC -fPIE -fvectorize -Wall -fstack-protector -fexceptions -fno-strict-aliasing -Wno-deprecated-register -DZT_NO_TYPE_PUNNING=1
+APP_PLATFORM := android-14
+APP_ABI := all
diff --git a/java/jni/ZT1_jnicache.cpp b/java/jni/ZT1_jnicache.cpp
deleted file mode 100644
index d8141058..00000000
--- a/java/jni/ZT1_jnicache.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include "ZT_jnicache.h"
-#include "ZT_jniutils.h"
-
-JniCache::JniCache()
- : m_jvm(NULL)
- , m_classes()
- , m_fields()
- , m_staticFields()
- , m_methods()
- , m_staticMethods()
-{
- LOGV("JNI Cache Created");
-}
-
-JniCache::JniCache(JavaVM *jvm)
- : m_jvm(jvm)
- , m_classes()
- , m_fields()
- , m_staticFields()
- , m_methods()
- , m_staticMethods()
-{
- LOGV("JNI Cache Created");
-}
-
-JniCache::~JniCache()
-{
- LOGV("JNI Cache Destroyed");
- clearCache();
-}
-
-void JniCache::clearCache()
-{
- if(m_jvm)
- {
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- return;
-
- for(ClassMap::iterator iter = m_classes.begin(), end = m_classes.end();
- iter != end; ++iter)
- {
- env->DeleteGlobalRef(iter->second);
- }
- }
-
- m_classes.clear();
- m_fields.clear();
- m_staticFields.clear();
- m_methods.clear();
- m_staticMethods.clear();
-}
-
-void JniCache::setJavaVM(JavaVM *jvm)
-{
- LOGV("Assigned JVM to object");
- m_jvm = jvm;
-}
-
-
-jclass JniCache::findClass(const std::string &name)
-{
- if(!m_jvm)
- return NULL;
-
- ClassMap::iterator found = m_classes.find(name);
-
- if(found == m_classes.end())
- {
- // get the class from the JVM
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- LOGE("Error retreiving JNI Environment");
- return NULL;
- }
-
- jclass localCls = env->FindClass(name.c_str());
- if(env->ExceptionCheck())
- {
- LOGE("Error finding class: %s", name.c_str());
- return NULL;
- }
-
- jclass cls = (jclass)env->NewGlobalRef(localCls);
-
- m_classes.insert(std::make_pair(name, cls));
-
- return cls;
- }
-
- LOGV("Returning cached %s", name.c_str());
- return found->second;
-}
-
-
-jmethodID JniCache::findMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
-{
- if(!m_jvm)
- return NULL;
-
- std::string id = methodName + methodSig;
-
- MethodMap::iterator found = m_methods.find(id);
- if(found == m_methods.end())
- {
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- return NULL;
- }
-
- jmethodID mid = env->GetMethodID(cls, methodName.c_str(), methodSig.c_str());
- if(env->ExceptionCheck())
- {
- return NULL;
- }
-
- m_methods.insert(std::make_pair(id, mid));
-
- return mid;
- }
-
- return found->second;
-}
-
-jmethodID JniCache::findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
-{
- if(!m_jvm)
- return NULL;
-
- std::string id = methodName + methodSig;
-
- MethodMap::iterator found = m_staticMethods.find(id);
- if(found == m_staticMethods.end())
- {
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- return NULL;
- }
-
- jmethodID mid = env->GetStaticMethodID(cls, methodName.c_str(), methodSig.c_str());
- if(env->ExceptionCheck())
- {
- return NULL;
- }
-
- m_staticMethods.insert(std::make_pair(id, mid));
-
- return mid;
- }
-
- return found->second;
-}
-
-jfieldID JniCache::findField(jclass cls, const std::string &fieldName, const std::string &typeStr)
-{
- if(!m_jvm)
- return NULL;
-
- std::string id = fieldName + typeStr;
-
- FieldMap::iterator found = m_fields.find(id);
- if(found == m_fields.end())
- {
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- return NULL;
- }
-
- jfieldID fid = env->GetFieldID(cls, fieldName.c_str(), typeStr.c_str());
- if(env->ExceptionCheck())
- {
- return NULL;
- }
-
- m_fields.insert(std::make_pair(id, fid));
-
- return fid;
- }
-
- return found->second;
-}
-
-jfieldID JniCache::findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr)
-{
- if(!m_jvm)
- return NULL;
-
- std::string id = fieldName + typeStr;
-
- FieldMap::iterator found = m_staticFields.find(id);
- if(found == m_staticFields.end())
- {
- JNIEnv *env = NULL;
- if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
- {
- return NULL;
- }
-
- jfieldID fid = env->GetStaticFieldID(cls, fieldName.c_str(), typeStr.c_str());
- if(env->ExceptionCheck())
- {
- return NULL;
- }
-
- m_staticFields.insert(std::make_pair(id, fid));
-
- return fid;
- }
-
- return found->second;
-} \ No newline at end of file
diff --git a/java/jni/ZT_jnilookup.cpp b/java/jni/ZT_jnilookup.cpp
new file mode 100644
index 00000000..be52a366
--- /dev/null
+++ b/java/jni/ZT_jnilookup.cpp
@@ -0,0 +1,158 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include "ZT_jnilookup.h"
+#include "ZT_jniutils.h"
+
+JniLookup::JniLookup()
+ : m_jvm(NULL)
+{
+ LOGV("JNI Cache Created");
+}
+
+JniLookup::JniLookup(JavaVM *jvm)
+ : m_jvm(jvm)
+{
+ LOGV("JNI Cache Created");
+}
+
+JniLookup::~JniLookup()
+{
+ LOGV("JNI Cache Destroyed");
+}
+
+
+void JniLookup::setJavaVM(JavaVM *jvm)
+{
+ LOGV("Assigned JVM to object");
+ m_jvm = jvm;
+}
+
+
+jclass JniLookup::findClass(const std::string &name)
+{
+ if(!m_jvm)
+ return NULL;
+
+ // get the class from the JVM
+ JNIEnv *env = NULL;
+ if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+ {
+ LOGE("Error retreiving JNI Environment");
+ return NULL;
+ }
+
+ jclass cls = env->FindClass(name.c_str());
+ if(env->ExceptionCheck())
+ {
+ LOGE("Error finding class: %s", name.c_str());
+ return NULL;
+ }
+
+ return cls;
+}
+
+
+jmethodID JniLookup::findMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
+{
+ if(!m_jvm)
+ return NULL;
+
+ JNIEnv *env = NULL;
+ if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+ {
+ return NULL;
+ }
+
+ jmethodID mid = env->GetMethodID(cls, methodName.c_str(), methodSig.c_str());
+ if(env->ExceptionCheck())
+ {
+ return NULL;
+ }
+
+ return mid;
+}
+
+jmethodID JniLookup::findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
+{
+ if(!m_jvm)
+ return NULL;
+
+ JNIEnv *env = NULL;
+ if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+ {
+ return NULL;
+ }
+
+ jmethodID mid = env->GetStaticMethodID(cls, methodName.c_str(), methodSig.c_str());
+ if(env->ExceptionCheck())
+ {
+ return NULL;
+ }
+
+ return mid;
+}
+
+jfieldID JniLookup::findField(jclass cls, const std::string &fieldName, const std::string &typeStr)
+{
+ if(!m_jvm)
+ return NULL;
+
+ JNIEnv *env = NULL;
+ if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+ {
+ return NULL;
+ }
+
+ jfieldID fid = env->GetFieldID(cls, fieldName.c_str(), typeStr.c_str());
+ if(env->ExceptionCheck())
+ {
+ return NULL;
+ }
+
+ return fid;
+}
+
+jfieldID JniLookup::findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr)
+{
+ if(!m_jvm)
+ return NULL;
+
+ JNIEnv *env = NULL;
+ if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+ {
+ return NULL;
+ }
+
+ jfieldID fid = env->GetStaticFieldID(cls, fieldName.c_str(), typeStr.c_str());
+ if(env->ExceptionCheck())
+ {
+ return NULL;
+ }
+
+ return fid;
+} \ No newline at end of file
diff --git a/java/jni/ZT1_jnicache.h b/java/jni/ZT_jnilookup.h
index 001c13fe..f5bd97d7 100644
--- a/java/jni/ZT1_jnicache.h
+++ b/java/jni/ZT_jnilookup.h
@@ -25,8 +25,8 @@
* LLC. Start here: http://www.zerotier.com/
*/
-#ifndef ZT_JNICACHE_H_
-#define ZT_JNICACHE_H_
+#ifndef ZT_JNILOOKUP_H_
+#define ZT_JNILOOKUP_H_
#include <jni.h>
#include <map>
@@ -34,14 +34,13 @@
-class JniCache {
+class JniLookup {
public:
- JniCache();
- JniCache(JavaVM *jvm);
- ~JniCache();
+ JniLookup();
+ JniLookup(JavaVM *jvm);
+ ~JniLookup();
void setJavaVM(JavaVM *jvm);
- void clearCache();
jclass findClass(const std::string &name);
jmethodID findMethod(jclass cls, const std::string &methodName, const std::string &methodSig);
@@ -49,17 +48,7 @@ public:
jfieldID findField(jclass cls, const std::string &fieldName, const std::string &typeStr);
jfieldID findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr);
private:
- typedef std::map<std::string, jmethodID> MethodMap;
- typedef std::map<std::string, jfieldID> FieldMap;
- typedef std::map<std::string, jclass> ClassMap;
-
JavaVM *m_jvm;
- ClassMap m_classes;
- FieldMap m_fields;
- FieldMap m_staticFields;
- MethodMap m_methods;
- MethodMap m_staticMethods;
-
};
#endif \ No newline at end of file
diff --git a/java/jni/ZT1_jniutils.cpp b/java/jni/ZT_jniutils.cpp
index 794a0624..ae1aa929 100644
--- a/java/jni/ZT1_jniutils.cpp
+++ b/java/jni/ZT_jniutils.cpp
@@ -1,9 +1,9 @@
#include "ZT_jniutils.h"
-#include "ZT_jnicache.h"
+#include "ZT_jnilookup.h"
#include <string>
#include <assert.h>
-extern JniCache cache;
+extern JniLookup lookup;
#ifdef __cplusplus
extern "C" {
@@ -15,7 +15,7 @@ jobject createResultObject(JNIEnv *env, ZT_ResultCode code)
jobject resultObject = NULL;
- resultClass = cache.findClass("com/zerotier/sdk/ResultCode");
+ resultClass = lookup.findClass("com/zerotier/sdk/ResultCode");
if(resultClass == NULL)
{
LOGE("Couldnt find ResultCode class");
@@ -48,7 +48,7 @@ jobject createResultObject(JNIEnv *env, ZT_ResultCode code)
break;
}
- jfieldID enumField = cache.findStaticField(resultClass, fieldName.c_str(), "Lcom/zerotier/sdk/ResultCode;");
+ jfieldID enumField = lookup.findStaticField(resultClass, fieldName.c_str(), "Lcom/zerotier/sdk/ResultCode;");
if(env->ExceptionCheck() || enumField == NULL)
{
LOGE("Error on FindStaticField");
@@ -68,7 +68,7 @@ jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status)
{
jobject statusObject = NULL;
- jclass statusClass = cache.findClass("com/zerotier/sdk/VirtualNetworkStatus");
+ jclass statusClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkStatus");
if(statusClass == NULL)
{
return NULL; // exception thrown
@@ -97,7 +97,7 @@ jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status)
break;
}
- jfieldID enumField = cache.findStaticField(statusClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkStatus;");
+ jfieldID enumField = lookup.findStaticField(statusClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkStatus;");
statusObject = env->GetStaticObjectField(statusClass, enumField);
@@ -109,7 +109,7 @@ jobject createEvent(JNIEnv *env, ZT_Event event)
jclass eventClass = NULL;
jobject eventObject = NULL;
- eventClass = cache.findClass("com/zerotier/sdk/Event");
+ eventClass = lookup.findClass("com/zerotier/sdk/Event");
if(eventClass == NULL)
{
return NULL;
@@ -133,21 +133,12 @@ jobject createEvent(JNIEnv *env, ZT_Event event)
case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION:
fieldName = "EVENT_FATAL_ERROR_IDENTITY_COLLISION";
break;
- case ZT_EVENT_SAW_MORE_RECENT_VERSION:
- fieldName = "EVENT_SAW_MORE_RECENT_VERSION";
- break;
- case ZT_EVENT_AUTHENTICATION_FAILURE:
- fieldName = "EVENT_AUTHENTICATION_FAILURE";
- break;
- case ZT_EVENT_INVALID_PACKET:
- fieldName = "EVENT_INVALID_PACKET";
- break;
case ZT_EVENT_TRACE:
fieldName = "EVENT_TRACE";
break;
}
- jfieldID enumField = cache.findStaticField(eventClass, fieldName.c_str(), "Lcom/zerotier/sdk/Event;");
+ jfieldID enumField = lookup.findStaticField(eventClass, fieldName.c_str(), "Lcom/zerotier/sdk/Event;");
eventObject = env->GetStaticObjectField(eventClass, enumField);
@@ -159,7 +150,7 @@ jobject createPeerRole(JNIEnv *env, ZT_PeerRole role)
jclass peerRoleClass = NULL;
jobject peerRoleObject = NULL;
- peerRoleClass = cache.findClass("com/zerotier/sdk/PeerRole");
+ peerRoleClass = lookup.findClass("com/zerotier/sdk/PeerRole");
if(peerRoleClass == NULL)
{
return NULL;
@@ -171,15 +162,15 @@ jobject createPeerRole(JNIEnv *env, ZT_PeerRole role)
case ZT_PEER_ROLE_LEAF:
fieldName = "PEER_ROLE_LEAF";
break;
- case ZT_PEER_ROLE_HUB:
- fieldName = "PEER_ROLE_HUB";
+ case ZT_PEER_ROLE_RELAY:
+ fieldName = "PEER_ROLE_RELAY";
break;
- case ZT_PEER_ROLE_ROOTSERVER:
- fieldName = "PEER_ROLE_ROOTSERVER";
+ case ZT_PEER_ROLE_ROOT:
+ fieldName = "PEER_ROLE_ROOTS";
break;
}
- jfieldID enumField = cache.findStaticField(peerRoleClass, fieldName.c_str(), "Lcom/zerotier/sdk/PeerRole;");
+ jfieldID enumField = lookup.findStaticField(peerRoleClass, fieldName.c_str(), "Lcom/zerotier/sdk/PeerRole;");
peerRoleObject = env->GetStaticObjectField(peerRoleClass, enumField);
@@ -191,7 +182,7 @@ jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type)
jclass vntypeClass = NULL;
jobject vntypeObject = NULL;
- vntypeClass = cache.findClass("com/zerotier/sdk/VirtualNetworkType");
+ vntypeClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkType");
if(env->ExceptionCheck() || vntypeClass == NULL)
{
return NULL;
@@ -208,7 +199,7 @@ jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type)
break;
}
- jfieldID enumField = cache.findStaticField(vntypeClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkType;");
+ jfieldID enumField = lookup.findStaticField(vntypeClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkType;");
vntypeObject = env->GetStaticObjectField(vntypeClass, enumField);
return vntypeObject;
}
@@ -218,7 +209,7 @@ jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT_VirtualNetworkConfig
jclass vnetConfigOpClass = NULL;
jobject vnetConfigOpObject = NULL;
- vnetConfigOpClass = cache.findClass("com/zerotier/sdk/VirtualNetworkConfigOperation");
+ vnetConfigOpClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfigOperation");
if(env->ExceptionCheck() || vnetConfigOpClass == NULL)
{
return NULL;
@@ -241,7 +232,7 @@ jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT_VirtualNetworkConfig
break;
}
- jfieldID enumField = cache.findStaticField(vnetConfigOpClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkConfigOperation;");
+ jfieldID enumField = lookup.findStaticField(vnetConfigOpClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkConfigOperation;");
vnetConfigOpObject = env->GetStaticObjectField(vnetConfigOpClass, enumField);
return vnetConfigOpObject;
}
@@ -252,14 +243,14 @@ jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr)
jclass inetAddressClass = NULL;
jmethodID inetAddress_getByAddress = NULL;
- inetAddressClass = cache.findClass("java/net/InetAddress");
+ inetAddressClass = lookup.findClass("java/net/InetAddress");
if(env->ExceptionCheck() || inetAddressClass == NULL)
{
LOGE("Error finding InetAddress class");
return NULL;
}
- inetAddress_getByAddress = cache.findStaticMethod(
+ inetAddress_getByAddress = lookup.findStaticMethod(
inetAddressClass, "getByAddress", "([B)Ljava/net/InetAddress;");
if(env->ExceptionCheck() || inetAddress_getByAddress == NULL)
{
@@ -315,7 +306,7 @@ jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr)
jclass inetSocketAddressClass = NULL;
jmethodID inetSocketAddress_constructor = NULL;
- inetSocketAddressClass = cache.findClass("java/net/InetSocketAddress");
+ inetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress");
if(env->ExceptionCheck() || inetSocketAddressClass == NULL)
{
LOGE("Error finding InetSocketAddress Class");
@@ -330,7 +321,7 @@ jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr)
return NULL;
}
- inetSocketAddress_constructor = cache.findMethod(
+ inetSocketAddress_constructor = lookup.findMethod(
inetSocketAddressClass, "<init>", "(Ljava/net/InetAddress;I)V");
if(env->ExceptionCheck() || inetSocketAddress_constructor == NULL)
{
@@ -343,18 +334,18 @@ jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr)
{
case AF_INET6:
{
- LOGD("IPV6 Address");
+ LOGV("IPV6 Address");
sockaddr_in6 *ipv6 = (sockaddr_in6*)&addr;
port = ntohs(ipv6->sin6_port);
- LOGD("Port %d", port);
+ LOGV("Port %d", port);
}
break;
case AF_INET:
{
- LOGD("IPV4 Address");
+ LOGV("IPV4 Address");
sockaddr_in *ipv4 = (sockaddr_in*)&addr;
port = ntohs(ipv4->sin_port);
- LOGD("Port: %d", port);
+ LOGV("Port: %d", port);
}
break;
default:
@@ -380,13 +371,13 @@ jobject newMulticastGroup(JNIEnv *env, const ZT_MulticastGroup &mc)
jfieldID macField = NULL;
jfieldID adiField = NULL;
- multicastGroupClass = cache.findClass("com/zerotier/sdk/MulticastGroup");
+ multicastGroupClass = lookup.findClass("com/zerotier/sdk/MulticastGroup");
if(env->ExceptionCheck() || multicastGroupClass == NULL)
{
return NULL;
}
- multicastGroup_constructor = cache.findMethod(
+ multicastGroup_constructor = lookup.findMethod(
multicastGroupClass, "<init>", "()V");
if(env->ExceptionCheck() || multicastGroup_constructor == NULL)
{
@@ -399,13 +390,13 @@ jobject newMulticastGroup(JNIEnv *env, const ZT_MulticastGroup &mc)
return NULL;
}
- macField = cache.findField(multicastGroupClass, "mac", "J");
+ macField = lookup.findField(multicastGroupClass, "mac", "J");
if(env->ExceptionCheck() || macField == NULL)
{
return NULL;
}
- adiField = cache.findField(multicastGroupClass, "adi", "J");
+ adiField = lookup.findField(multicastGroupClass, "adi", "J");
if(env->ExceptionCheck() || adiField == NULL)
{
return NULL;
@@ -425,62 +416,54 @@ jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp)
jfieldID addressField = NULL;
jfieldID lastSendField = NULL;
jfieldID lastReceiveField = NULL;
- jfieldID fixedField = NULL;
jfieldID activeField = NULL;
jfieldID preferredField = NULL;
jmethodID ppp_constructor = NULL;
- pppClass = cache.findClass("com/zerotier/sdk/PeerPhysicalPath");
+ pppClass = lookup.findClass("com/zerotier/sdk/PeerPhysicalPath");
if(env->ExceptionCheck() || pppClass == NULL)
{
LOGE("Error finding PeerPhysicalPath class");
return NULL;
}
- addressField = cache.findField(pppClass, "address", "Ljava/net/InetSocketAddress;");
+ addressField = lookup.findField(pppClass, "address", "Ljava/net/InetSocketAddress;");
if(env->ExceptionCheck() || addressField == NULL)
{
LOGE("Error finding address field");
return NULL;
}
- lastSendField = cache.findField(pppClass, "lastSend", "J");
+ lastSendField = lookup.findField(pppClass, "lastSend", "J");
if(env->ExceptionCheck() || lastSendField == NULL)
{
LOGE("Error finding lastSend field");
return NULL;
}
- lastReceiveField = cache.findField(pppClass, "lastReceive", "J");
+ lastReceiveField = lookup.findField(pppClass, "lastReceive", "J");
if(env->ExceptionCheck() || lastReceiveField == NULL)
{
LOGE("Error finding lastReceive field");
return NULL;
}
- fixedField = cache.findField(pppClass, "fixed", "Z");
- if(env->ExceptionCheck() || fixedField == NULL)
- {
- LOGE("Error finding fixed field");
- return NULL;
- }
-
- activeField = cache.findField(pppClass, "active", "Z");
+ activeField = lookup.findField(pppClass, "active", "Z");
if(env->ExceptionCheck() || activeField == NULL)
{
LOGE("Error finding active field");
return NULL;
}
- preferredField = cache.findField(pppClass, "preferred", "Z");
+ preferredField = lookup.findField(pppClass, "preferred", "Z");
if(env->ExceptionCheck() || preferredField == NULL)
{
LOGE("Error finding preferred field");
return NULL;
}
- ppp_constructor = cache.findMethod(pppClass, "<init>", "()V");
+ ppp_constructor = lookup.findMethod(pppClass, "<init>", "()V");
if(env->ExceptionCheck() || ppp_constructor == NULL)
{
LOGE("Error finding PeerPhysicalPath constructor");
@@ -503,7 +486,6 @@ jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp)
env->SetObjectField(pppObject, addressField, addressObject);
env->SetLongField(pppObject, lastSendField, ppp.lastSend);
env->SetLongField(pppObject, lastReceiveField, ppp.lastReceive);
- env->SetBooleanField(pppObject, fixedField, ppp.fixed);
env->SetBooleanField(pppObject, activeField, ppp.active);
env->SetBooleanField(pppObject, preferredField, ppp.preferred);
@@ -532,77 +514,77 @@ jobject newPeer(JNIEnv *env, const ZT_Peer &peer)
jmethodID peer_constructor = NULL;
- peerClass = cache.findClass("com/zerotier/sdk/Peer");
+ peerClass = lookup.findClass("com/zerotier/sdk/Peer");
if(env->ExceptionCheck() || peerClass == NULL)
{
LOGE("Error finding Peer class");
return NULL;
}
- addressField = cache.findField(peerClass, "address", "J");
+ addressField = lookup.findField(peerClass, "address", "J");
if(env->ExceptionCheck() || addressField == NULL)
{
LOGE("Error finding address field of Peer object");
return NULL;
}
- lastUnicastFrameField = cache.findField(peerClass, "lastUnicastFrame", "J");
+ lastUnicastFrameField = lookup.findField(peerClass, "lastUnicastFrame", "J");
if(env->ExceptionCheck() || lastUnicastFrameField == NULL)
{
LOGE("Error finding lastUnicastFrame field of Peer object");
return NULL;
}
- lastMulticastFrameField = cache.findField(peerClass, "lastMulticastFrame", "J");
+ lastMulticastFrameField = lookup.findField(peerClass, "lastMulticastFrame", "J");
if(env->ExceptionCheck() || lastMulticastFrameField == NULL)
{
LOGE("Error finding lastMulticastFrame field of Peer object");
return NULL;
}
- versionMajorField = cache.findField(peerClass, "versionMajor", "I");
+ versionMajorField = lookup.findField(peerClass, "versionMajor", "I");
if(env->ExceptionCheck() || versionMajorField == NULL)
{
LOGE("Error finding versionMajor field of Peer object");
return NULL;
}
- versionMinorField = cache.findField(peerClass, "versionMinor", "I");
+ versionMinorField = lookup.findField(peerClass, "versionMinor", "I");
if(env->ExceptionCheck() || versionMinorField == NULL)
{
LOGE("Error finding versionMinor field of Peer object");
return NULL;
}
- versionRevField = cache.findField(peerClass, "versionRev", "I");
+ versionRevField = lookup.findField(peerClass, "versionRev", "I");
if(env->ExceptionCheck() || versionRevField == NULL)
{
LOGE("Error finding versionRev field of Peer object");
return NULL;
}
- latencyField = cache.findField(peerClass, "latency", "I");
+ latencyField = lookup.findField(peerClass, "latency", "I");
if(env->ExceptionCheck() || latencyField == NULL)
{
LOGE("Error finding latency field of Peer object");
return NULL;
}
- roleField = cache.findField(peerClass, "role", "Lcom/zerotier/sdk/PeerRole;");
+ roleField = lookup.findField(peerClass, "role", "Lcom/zerotier/sdk/PeerRole;");
if(env->ExceptionCheck() || roleField == NULL)
{
LOGE("Error finding role field of Peer object");
return NULL;
}
- pathsField = cache.findField(peerClass, "paths", "[Lcom/zerotier/sdk/PeerPhysicalPath;");
+ pathsField = lookup.findField(peerClass, "paths", "[Lcom/zerotier/sdk/PeerPhysicalPath;");
if(env->ExceptionCheck() || pathsField == NULL)
{
LOGE("Error finding paths field of Peer object");
return NULL;
}
- peer_constructor = cache.findMethod(peerClass, "<init>", "()V");
+ peer_constructor = lookup.findMethod(peerClass, "<init>", "()V");
if(env->ExceptionCheck() || peer_constructor == NULL)
{
LOGE("Error finding Peer constructor");
@@ -625,7 +607,7 @@ jobject newPeer(JNIEnv *env, const ZT_Peer &peer)
env->SetIntField(peerObject, latencyField, peer.latency);
env->SetObjectField(peerObject, roleField, createPeerRole(env, peer.role));
- jclass peerPhysicalPathClass = cache.findClass("com/zerotier/sdk/PeerPhysicalPath");
+ jclass peerPhysicalPathClass = lookup.findClass("com/zerotier/sdk/PeerPhysicalPath");
if(env->ExceptionCheck() || peerPhysicalPathClass == NULL)
{
LOGE("Error finding PeerPhysicalPath class");
@@ -675,14 +657,14 @@ jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &vnetConfig)
jfieldID multicastSubscriptionsField = NULL;
jfieldID assignedAddressesField = NULL;
- vnetConfigClass = cache.findClass("com/zerotier/sdk/VirtualNetworkConfig");
+ vnetConfigClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfig");
if(vnetConfigClass == NULL)
{
LOGE("Couldn't find com.zerotier.sdk.VirtualNetworkConfig");
return NULL;
}
- vnetConfig_constructor = cache.findMethod(
+ vnetConfig_constructor = lookup.findMethod(
vnetConfigClass, "<init>", "()V");
if(env->ExceptionCheck() || vnetConfig_constructor == NULL)
{
@@ -697,98 +679,98 @@ jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &vnetConfig)
return NULL;
}
- nwidField = cache.findField(vnetConfigClass, "nwid", "J");
+ nwidField = lookup.findField(vnetConfigClass, "nwid", "J");
if(env->ExceptionCheck() || nwidField == NULL)
{
LOGE("Error getting nwid field");
return NULL;
}
- macField = cache.findField(vnetConfigClass, "mac", "J");
+ macField = lookup.findField(vnetConfigClass, "mac", "J");
if(env->ExceptionCheck() || macField == NULL)
{
LOGE("Error getting mac field");
return NULL;
}
- nameField = cache.findField(vnetConfigClass, "name", "Ljava/lang/String;");
+ nameField = lookup.findField(vnetConfigClass, "name", "Ljava/lang/String;");
if(env->ExceptionCheck() || nameField == NULL)
{
LOGE("Error getting name field");
return NULL;
}
- statusField = cache.findField(vnetConfigClass, "status", "Lcom/zerotier/sdk/VirtualNetworkStatus;");
+ statusField = lookup.findField(vnetConfigClass, "status", "Lcom/zerotier/sdk/VirtualNetworkStatus;");
if(env->ExceptionCheck() || statusField == NULL)
{
LOGE("Error getting status field");
return NULL;
}
- typeField = cache.findField(vnetConfigClass, "type", "Lcom/zerotier/sdk/VirtualNetworkType;");
+ typeField = lookup.findField(vnetConfigClass, "type", "Lcom/zerotier/sdk/VirtualNetworkType;");
if(env->ExceptionCheck() || typeField == NULL)
{
LOGE("Error getting type field");
return NULL;
}
- mtuField = cache.findField(vnetConfigClass, "mtu", "I");
+ mtuField = lookup.findField(vnetConfigClass, "mtu", "I");
if(env->ExceptionCheck() || mtuField == NULL)
{
LOGE("Error getting mtu field");
return NULL;
}
- dhcpField = cache.findField(vnetConfigClass, "dhcp", "Z");
+ dhcpField = lookup.findField(vnetConfigClass, "dhcp", "Z");
if(env->ExceptionCheck() || dhcpField == NULL)
{
LOGE("Error getting dhcp field");
return NULL;
}
- bridgeField = cache.findField(vnetConfigClass, "bridge", "Z");
+ bridgeField = lookup.findField(vnetConfigClass, "bridge", "Z");
if(env->ExceptionCheck() || bridgeField == NULL)
{
LOGE("Error getting bridge field");
return NULL;
}
- broadcastEnabledField = cache.findField(vnetConfigClass, "broadcastEnabled", "Z");
+ broadcastEnabledField = lookup.findField(vnetConfigClass, "broadcastEnabled", "Z");
if(env->ExceptionCheck() || broadcastEnabledField == NULL)
{
LOGE("Error getting broadcastEnabled field");
return NULL;
}
- portErrorField = cache.findField(vnetConfigClass, "portError", "I");
+ portErrorField = lookup.findField(vnetConfigClass, "portError", "I");
if(env->ExceptionCheck() || portErrorField == NULL)
{
LOGE("Error getting portError field");
return NULL;
}
- enabledField = cache.findField(vnetConfigClass, "enabled", "Z");
+ enabledField = lookup.findField(vnetConfigClass, "enabled", "Z");
if(env->ExceptionCheck() || enabledField == NULL)
{
LOGE("Error getting enabled field");
return NULL;
}
- netconfRevisionField = cache.findField(vnetConfigClass, "netconfRevision", "J");
+ netconfRevisionField = lookup.findField(vnetConfigClass, "netconfRevision", "J");
if(env->ExceptionCheck() || netconfRevisionField == NULL)
{
LOGE("Error getting netconfRevision field");
return NULL;
}
- multicastSubscriptionsField = cache.findField(vnetConfigClass, "multicastSubscriptions", "[Lcom/zerotier/sdk/MulticastGroup;");
+ multicastSubscriptionsField = lookup.findField(vnetConfigClass, "multicastSubscriptions", "[Lcom/zerotier/sdk/MulticastGroup;");
if(env->ExceptionCheck() || multicastSubscriptionsField == NULL)
{
LOGE("Error getting multicastSubscriptions field");
return NULL;
}
- assignedAddressesField = cache.findField(vnetConfigClass, "assignedAddresses", "[Ljava/net/InetSocketAddress;");
+ assignedAddressesField = lookup.findField(vnetConfigClass, "assignedAddresses", "[Ljava/net/InetSocketAddress;");
if(env->ExceptionCheck() || assignedAddressesField == NULL)
{
LOGE("Error getting assignedAddresses field");
@@ -818,13 +800,14 @@ jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &vnetConfig)
}
env->SetObjectField(vnetConfigObj, typeField, typeObject);
- env->SetIntField(vnetConfigObj, mtuField, vnetConfig.mtu);
+ env->SetIntField(vnetConfigObj, mtuField, (int)vnetConfig.mtu);
env->SetBooleanField(vnetConfigObj, dhcpField, vnetConfig.dhcp);
env->SetBooleanField(vnetConfigObj, bridgeField, vnetConfig.bridge);
env->SetBooleanField(vnetConfigObj, broadcastEnabledField, vnetConfig.broadcastEnabled);
+ env->SetBooleanField(vnetConfigObj, enabledField, vnetConfig.enabled);
env->SetIntField(vnetConfigObj, portErrorField, vnetConfig.portError);
- jclass multicastGroupClass = cache.findClass("com/zerotier/sdk/MulticastGroup");
+ jclass multicastGroupClass = lookup.findClass("com/zerotier/sdk/MulticastGroup");
if(env->ExceptionCheck() || multicastGroupClass == NULL)
{
LOGE("Error finding MulticastGroup class");
@@ -849,7 +832,7 @@ jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &vnetConfig)
}
env->SetObjectField(vnetConfigObj, multicastSubscriptionsField, mcastSubsArrayObj);
- jclass inetSocketAddressClass = cache.findClass("java/net/InetSocketAddress");
+ jclass inetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress");
if(env->ExceptionCheck() || inetSocketAddressClass == NULL)
{
LOGE("Error finding InetSocketAddress class");
@@ -886,13 +869,13 @@ jobject newVersion(JNIEnv *env, int major, int minor, int rev, long featureFlags
jclass versionClass = NULL;
jmethodID versionConstructor = NULL;
- versionClass = cache.findClass("com/zerotier/sdk/Version");
+ versionClass = lookup.findClass("com/zerotier/sdk/Version");
if(env->ExceptionCheck() || versionClass == NULL)
{
return NULL;
}
- versionConstructor = cache.findMethod(
+ versionConstructor = lookup.findMethod(
versionClass, "<init>", "()V");
if(env->ExceptionCheck() || versionConstructor == NULL)
{
@@ -911,25 +894,25 @@ jobject newVersion(JNIEnv *env, int major, int minor, int rev, long featureFlags
jfieldID revisionField = NULL;
jfieldID featureFlagsField = NULL;
- majorField = cache.findField(versionClass, "major", "I");
+ majorField = lookup.findField(versionClass, "major", "I");
if(env->ExceptionCheck() || majorField == NULL)
{
return NULL;
}
- minorField = cache.findField(versionClass, "minor", "I");
+ minorField = lookup.findField(versionClass, "minor", "I");
if(env->ExceptionCheck() || minorField == NULL)
{
return NULL;
}
- revisionField = cache.findField(versionClass, "revision", "I");
+ revisionField = lookup.findField(versionClass, "revision", "I");
if(env->ExceptionCheck() || revisionField == NULL)
{
return NULL;
}
- featureFlagsField = cache.findField(versionClass, "featureFlags", "J");
+ featureFlagsField = lookup.findField(versionClass, "featureFlags", "J");
if(env->ExceptionCheck() || featureFlagsField == NULL)
{
return NULL;
diff --git a/java/jni/ZT1_jniutils.h b/java/jni/ZT_jniutils.h
index b76a28c2..b76a28c2 100644
--- a/java/jni/ZT1_jniutils.h
+++ b/java/jni/ZT_jniutils.h
diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp
index ff12708a..2c1b6807 100644
--- a/java/jni/com_zerotierone_sdk_Node.cpp
+++ b/java/jni/com_zerotierone_sdk_Node.cpp
@@ -27,17 +27,18 @@
#include "com_zerotierone_sdk_Node.h"
#include "ZT_jniutils.h"
-#include "ZT_jnicache.h"
+#include "ZT_jnilookup.h"
#include <ZeroTierOne.h>
+#include "Mutex.hpp"
#include <map>
#include <string>
#include <assert.h>
#include <string.h>
-// global static JNI Cache Object
-JniCache cache;
+// global static JNI Lookup Object
+JniLookup lookup;
#ifdef __cplusplus
extern "C" {
@@ -92,7 +93,7 @@ namespace {
enum ZT_VirtualNetworkConfigOperation operation,
const ZT_VirtualNetworkConfig *config)
{
- LOGD("VritualNetworkConfigFunctionCallback");
+ LOGV("VritualNetworkConfigFunctionCallback");
JniRef *ref = (JniRef*)userData;
JNIEnv *env = NULL;
ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
@@ -104,7 +105,7 @@ namespace {
return -1;
}
- jmethodID configListenerCallbackMethod = cache.findMethod(configListenerClass,
+ jmethodID configListenerCallbackMethod = lookup.findMethod(configListenerClass,
"onNetworkConfigurationUpdated",
"(JLcom/zerotier/sdk/VirtualNetworkConfigOperation;Lcom/zerotier/sdk/VirtualNetworkConfig;)I");
if(configListenerCallbackMethod == NULL)
@@ -133,7 +134,8 @@ namespace {
(jlong)nwid, operationObject, networkConfigObject);
}
- void VirtualNetworkFrameFunctionCallback(ZT_Node *node,void *userData,
+ void VirtualNetworkFrameFunctionCallback(ZT_Node *node,
+ void *userData,
uint64_t nwid,
uint64_t sourceMac,
uint64_t destMac,
@@ -142,7 +144,9 @@ namespace {
const void *frameData,
unsigned int frameLength)
{
- LOGD("VirtualNetworkFrameFunctionCallback");
+ LOGV("VirtualNetworkFrameFunctionCallback");
+ unsigned char* local = (unsigned char*)frameData;
+ LOGV("Type Bytes: 0x%02x%02x", local[12], local[13]);
JniRef *ref = (JniRef*)userData;
assert(ref->node == node);
JNIEnv *env = NULL;
@@ -156,7 +160,7 @@ namespace {
return;
}
- jmethodID frameListenerCallbackMethod = cache.findMethod(
+ jmethodID frameListenerCallbackMethod = lookup.findMethod(
frameListenerClass,
"onVirtualNetworkFrame", "(JJJJJ[B)V");
if(env->ExceptionCheck() || frameListenerCallbackMethod == NULL)
@@ -172,9 +176,9 @@ namespace {
return;
}
- jbyte *data = env->GetByteArrayElements(dataArray, NULL);
+ void *data = env->GetPrimitiveArrayCritical(dataArray, NULL);
memcpy(data, frameData, frameLength);
- env->ReleaseByteArrayElements(dataArray, data, 0);
+ env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
if(env->ExceptionCheck())
{
@@ -186,11 +190,18 @@ namespace {
}
- void EventCallback(ZT_Node *node,void *userData,enum ZT_Event event, const void *data)
+ void EventCallback(ZT_Node *node,
+ void *userData,
+ enum ZT_Event event,
+ const void *data)
{
- LOGD("EventCallback");
+ LOGV("EventCallback");
JniRef *ref = (JniRef*)userData;
- assert(ref->node == node);
+ if(ref->node != node && event != ZT_EVENT_UP)
+ {
+ LOGE("Nodes not equal. ref->node %p, node %p. Event: %d", ref->node, node, event);
+ return;
+ }
JNIEnv *env = NULL;
ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
@@ -202,7 +213,7 @@ namespace {
return;
}
- jmethodID onEventMethod = cache.findMethod(eventListenerClass,
+ jmethodID onEventMethod = lookup.findMethod(eventListenerClass,
"onEvent", "(Lcom/zerotier/sdk/Event;)V");
if(onEventMethod == NULL)
{
@@ -210,26 +221,7 @@ namespace {
return;
}
-
- jmethodID onOutOfDateMethod = cache.findMethod(eventListenerClass,
- "onOutOfDate", "(Lcom/zerotier/sdk/Version;)V");
- if(onOutOfDateMethod == NULL)
- {
- LOGE("Couldn't find onOutOfDate method");
- return;
- }
-
-
- jmethodID onNetworkErrorMethod = cache.findMethod(eventListenerClass,
- "onNetworkError", "(Lcom/zerotier/sdk/Event;Ljava/net/InetSocketAddress;)V");
- if(onNetworkErrorMethod == NULL)
- {
- LOGE("Couldn't find onNetworkError method");
- return;
- }
-
-
- jmethodID onTraceMethod = cache.findMethod(eventListenerClass,
+ jmethodID onTraceMethod = lookup.findMethod(eventListenerClass,
"onTrace", "(Ljava/lang/String;)V");
if(onTraceMethod == NULL)
{
@@ -246,39 +238,34 @@ namespace {
switch(event)
{
case ZT_EVENT_UP:
+ {
+ LOGD("Event Up");
+ env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ break;
+ }
case ZT_EVENT_OFFLINE:
+ {
+ LOGD("Event Offline");
+ env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ break;
+ }
case ZT_EVENT_ONLINE:
- case ZT_EVENT_DOWN:
- case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION:
{
- LOGV("Regular Event");
- // call onEvent()
+ LOGD("Event Online");
env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ break;
}
- break;
- case ZT_EVENT_SAW_MORE_RECENT_VERSION:
+ case ZT_EVENT_DOWN:
{
- LOGV("Version Event");
- // call onOutOfDate()
- if(data != NULL)
- {
- int *version = (int*)data;
- jobject verisonObj = newVersion(env, version[0], version[1], version[2], 0);
- env->CallVoidMethod(ref->eventListener, onOutOfDateMethod, verisonObj);
- }
+ LOGD("Event Down");
+ env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
+ break;
}
- break;
- case ZT_EVENT_AUTHENTICATION_FAILURE:
- case ZT_EVENT_INVALID_PACKET:
+ case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION:
{
- LOGV("Network Error Event");
- // call onNetworkError()
- if(data != NULL)
- {
- sockaddr_storage *addr = (sockaddr_storage*)data;
- jobject addressObj = newInetSocketAddress(env, *addr);
- env->CallVoidMethod(ref->eventListener, onNetworkErrorMethod, addressObj);
- }
+ LOGV("Identity Collision");
+ // call onEvent()
+ env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject);
}
break;
case ZT_EVENT_TRACE:
@@ -296,7 +283,8 @@ namespace {
}
}
- long DataStoreGetFunction(ZT_Node *node,void *userData,
+ long DataStoreGetFunction(ZT_Node *node,
+ void *userData,
const char *objectName,
void *buffer,
unsigned long bufferSize,
@@ -314,7 +302,7 @@ namespace {
return -2;
}
- jmethodID dataStoreGetCallbackMethod = cache.findMethod(
+ jmethodID dataStoreGetCallbackMethod = lookup.findMethod(
dataStoreGetClass,
"onDataStoreGet",
"(Ljava/lang/String;[BJ[J)J");
@@ -354,21 +342,22 @@ namespace {
if(retval > 0)
{
- jbyte *data = env->GetByteArrayElements(bufferObj, NULL);
+ void *data = env->GetPrimitiveArrayCritical(bufferObj, NULL);
memcpy(buffer, data, retval);
- env->ReleaseByteArrayElements(bufferObj, data, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(bufferObj, data, 0);
- jlong *objSize = env->GetLongArrayElements(objectSizeObj, NULL);
+ jlong *objSize = (jlong*)env->GetPrimitiveArrayCritical(objectSizeObj, NULL);
*out_objectSize = (unsigned long)objSize[0];
- env->ReleaseLongArrayElements(objectSizeObj, objSize, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(objectSizeObj, objSize, 0);
}
- LOGI("Out Object Size: %lu", *out_objectSize);
+ LOGV("Out Object Size: %lu", *out_objectSize);
return retval;
}
- int DataStorePutFunction(ZT_Node *node,void *userData,
+ int DataStorePutFunction(ZT_Node *node,
+ void *userData,
const char *objectName,
const void *buffer,
unsigned long bufferSize,
@@ -386,7 +375,7 @@ namespace {
return -1;
}
- jmethodID dataStorePutCallbackMethod = cache.findMethod(
+ jmethodID dataStorePutCallbackMethod = lookup.findMethod(
dataStorePutClass,
"onDataStorePut",
"(Ljava/lang/String;[BZ)I");
@@ -396,7 +385,7 @@ namespace {
return -2;
}
- jmethodID deleteMethod = cache.findMethod(dataStorePutClass,
+ jmethodID deleteMethod = lookup.findMethod(dataStorePutClass,
"onDelete", "(Ljava/lang/String;)I");
if(deleteMethod == NULL)
{
@@ -408,30 +397,40 @@ namespace {
if(buffer == NULL)
{
+ LOGD("JNI: Delete file: %s", objectName);
// delete operation
return env->CallIntMethod(
ref->dataStorePutListener, deleteMethod, nameStr);
}
else
{
+ LOGD("JNI: Write file: %s", objectName);
// set operation
jbyteArray bufferObj = env->NewByteArray(bufferSize);
+ if(env->ExceptionCheck() || bufferObj == NULL)
+ {
+ LOGE("Error creating byte array buffer!");
+ return -4;
+ }
+
env->SetByteArrayRegion(bufferObj, 0, bufferSize, (jbyte*)buffer);
bool bsecure = secure != 0;
-
return env->CallIntMethod(ref->dataStorePutListener,
dataStorePutCallbackMethod,
nameStr, bufferObj, bsecure);
}
}
- int WirePacketSendFunction(ZT_Node *node,void *userData,\
- const struct sockaddr_storage *address,
+ int WirePacketSendFunction(ZT_Node *node,
+ void *userData,
+ const struct sockaddr_storage *localAddress,
+ const struct sockaddr_storage *remoteAddress,
const void *buffer,
- unsigned int bufferSize)
+ unsigned int bufferSize,
+ unsigned int ttl)
{
- LOGD("WirePacketSendFunction(%p, %p, %d)", address, buffer, bufferSize);
+ LOGV("WirePacketSendFunction(%p, %p, %p, %d)", localAddress, remoteAddress, buffer, bufferSize);
JniRef *ref = (JniRef*)userData;
assert(ref->node == node);
@@ -446,28 +445,36 @@ namespace {
return -1;
}
- jmethodID packetSenderCallbackMethod = cache.findMethod(packetSenderClass,
- "onSendPacketRequested", "(Ljava/net/InetSocketAddress;[B)I");
+ jmethodID packetSenderCallbackMethod = lookup.findMethod(packetSenderClass,
+ "onSendPacketRequested", "(Ljava/net/InetSocketAddress;Ljava/net/InetSocketAddress;[BI)I");
if(packetSenderCallbackMethod == NULL)
{
LOGE("Couldn't find onSendPacketRequested method");
return -2;
}
- jobject addressObj = newInetSocketAddress(env, *address);
+ jobject localAddressObj = NULL;
+ if(memcmp(localAddress, &ZT_SOCKADDR_NULL, sizeof(sockaddr_storage)) != 0)
+ {
+ localAddressObj = newInetSocketAddress(env, *localAddress);
+ }
+
+ jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress);
jbyteArray bufferObj = env->NewByteArray(bufferSize);
env->SetByteArrayRegion(bufferObj, 0, bufferSize, (jbyte*)buffer);
- int retval = env->CallIntMethod(ref->packetSender, packetSenderCallbackMethod, addressObj, bufferObj);
+ int retval = env->CallIntMethod(ref->packetSender, packetSenderCallbackMethod, localAddressObj, remoteAddressObj, bufferObj);
- LOGD("JNI Packet Sender returned: %d", retval);
+ LOGV("JNI Packet Sender returned: %d", retval);
return retval;
}
typedef std::map<uint64_t, JniRef*> NodeMap;
static NodeMap nodeMap;
+ ZeroTier::Mutex nodeMapMutex;
ZT_Node* findNode(uint64_t nodeId)
{
+ ZeroTier::Mutex::Lock lock(nodeMapMutex);
NodeMap::iterator found = nodeMap.find(nodeId);
if(found != nodeMap.end())
{
@@ -480,13 +487,13 @@ namespace {
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
- cache.setJavaVM(vm);
+ lookup.setJavaVM(vm);
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
{
- cache.clearCache();
+
}
@@ -507,7 +514,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
env->GetJavaVM(&ref->jvm);
jclass cls = env->GetObjectClass(obj);
- jfieldID fid = cache.findField(
+ jfieldID fid = lookup.findField(
cls, "getListener", "Lcom/zerotier/sdk/DataStoreGetListener;");
if(fid == NULL)
@@ -522,7 +529,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
}
ref->dataStoreGetListener = env->NewGlobalRef(tmp);
- fid = cache.findField(
+ fid = lookup.findField(
cls, "putListener", "Lcom/zerotier/sdk/DataStorePutListener;");
if(fid == NULL)
@@ -537,7 +544,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
}
ref->dataStorePutListener = env->NewGlobalRef(tmp);
- fid = cache.findField(
+ fid = lookup.findField(
cls, "sender", "Lcom/zerotier/sdk/PacketSender;");
if(fid == NULL)
{
@@ -551,7 +558,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
}
ref->packetSender = env->NewGlobalRef(tmp);
- fid = cache.findField(
+ fid = lookup.findField(
cls, "frameListener", "Lcom/zerotier/sdk/VirtualNetworkFrameListener;");
if(fid == NULL)
{
@@ -565,7 +572,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
}
ref->frameListener = env->NewGlobalRef(tmp);
- fid = cache.findField(
+ fid = lookup.findField(
cls, "configListener", "Lcom/zerotier/sdk/VirtualNetworkConfigListener;");
if(fid == NULL)
{
@@ -579,7 +586,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
}
ref->configListener = env->NewGlobalRef(tmp);
- fid = cache.findField(
+ fid = lookup.findField(
cls, "eventListener", "Lcom/zerotier/sdk/EventListener;");
if(fid == NULL)
{
@@ -618,8 +625,10 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
return resultObject;
}
+ ZeroTier::Mutex::Lock lock(nodeMapMutex);
ref->node = node;
nodeMap.insert(std::make_pair(ref->id, ref));
+
return resultObject;
}
@@ -635,7 +644,12 @@ JNIEXPORT void JNICALL Java_com_zerotier_sdk_Node_node_1delete(
LOGV("Destroying ZT_Node struct");
uint64_t nodeId = (uint64_t)id;
- NodeMap::iterator found = nodeMap.find(nodeId);
+ NodeMap::iterator found;
+ {
+ ZeroTier::Mutex::Lock lock(nodeMapMutex);
+ found = nodeMap.find(nodeId);
+ }
+
if(found != nodeMap.end())
{
JniRef *ref = found->second;
@@ -693,7 +707,10 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame(
unsigned int vlanId = (unsigned int)in_vlanId;
unsigned int frameLength = env->GetArrayLength(in_frameData);
- jbyte *frameData =env->GetByteArrayElements(in_frameData, NULL);
+ void *frameData = env->GetPrimitiveArrayCritical(in_frameData, NULL);
+ void *localData = malloc(frameLength);
+ memcpy(localData, frameData, frameLength);
+ env->ReleasePrimitiveArrayCritical(in_frameData, frameData, 0);
uint64_t nextBackgroundTaskDeadline = 0;
@@ -705,15 +722,13 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame(
destMac,
etherType,
vlanId,
- (const void*)frameData,
+ (const void*)localData,
frameLength,
&nextBackgroundTaskDeadline);
- jlong *outDeadline = env->GetLongArrayElements(out_nextBackgroundTaskDeadline, NULL);
+ jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
- env->ReleaseLongArrayElements(out_nextBackgroundTaskDeadline, outDeadline, 0);
-
- env->ReleaseByteArrayElements(in_frameData, frameData, 0);
+ env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
return createResultObject(env, rc);
}
@@ -727,6 +742,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
JNIEnv *env, jobject obj,
jlong id,
jlong in_now,
+ jobject in_localAddress,
jobject in_remoteAddress,
jbyteArray in_packetData,
jlongArray out_nextBackgroundTaskDeadline)
@@ -736,26 +752,29 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
if(node == NULL)
{
// cannot find valid node. We should never get here.
+ LOGE("Couldn't find a valid node!");
return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
}
unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline);
if(nbtd_len < 1)
{
+ LOGE("nbtd_len < 1");
return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
}
uint64_t now = (uint64_t)in_now;
// get the java.net.InetSocketAddress class and getAddress() method
- jclass inetAddressClass = cache.findClass("java/net/InetAddress");
+ jclass inetAddressClass = lookup.findClass("java/net/InetAddress");
if(inetAddressClass == NULL)
{
+ LOGE("Can't find InetAddress class");
// can't find java.net.InetAddress
return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
}
- jmethodID getAddressMethod = cache.findMethod(
+ jmethodID getAddressMethod = lookup.findMethod(
inetAddressClass, "getAddress", "()[B");
if(getAddressMethod == NULL)
{
@@ -763,23 +782,29 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
}
- jclass InetSocketAddressClass = cache.findClass("java/net/InetSocketAddress");
+ jclass InetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress");
if(InetSocketAddressClass == NULL)
{
return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
}
- jmethodID inetSockGetAddressMethod = cache.findMethod(
+ jmethodID inetSockGetAddressMethod = lookup.findMethod(
InetSocketAddressClass, "getAddress", "()Ljava/net/InetAddress;");
- jobject addrObject = env->CallObjectMethod(in_remoteAddress, inetSockGetAddressMethod);
+ jobject localAddrObj = NULL;
+ if(in_localAddress != NULL)
+ {
+ localAddrObj = env->CallObjectMethod(in_localAddress, inetSockGetAddressMethod);
+ }
+
+ jobject remoteAddrObject = env->CallObjectMethod(in_remoteAddress, inetSockGetAddressMethod);
- if(addrObject == NULL)
+ if(remoteAddrObject == NULL)
{
return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
}
- jmethodID inetSock_getPort = cache.findMethod(
+ jmethodID inetSock_getPort = lookup.findMethod(
InetSocketAddressClass, "getPort", "()I");
if(env->ExceptionCheck() || inetSock_getPort == NULL)
@@ -789,7 +814,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
}
// call InetSocketAddress.getPort()
- int port = env->CallIntMethod(in_remoteAddress, inetSock_getPort);
+ int remotePort = env->CallIntMethod(in_remoteAddress, inetSock_getPort);
if(env->ExceptionCheck())
{
LOGE("Exception calling InetSocketAddress.getPort()");
@@ -797,18 +822,60 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
}
// Call InetAddress.getAddress()
- jbyteArray addressArray = (jbyteArray)env->CallObjectMethod(addrObject, getAddressMethod);
- if(addressArray == NULL)
+ jbyteArray remoteAddressArray = (jbyteArray)env->CallObjectMethod(remoteAddrObject, getAddressMethod);
+ if(remoteAddressArray == NULL)
{
+ LOGE("Unable to call getAddress()");
// unable to call getAddress()
return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
}
- unsigned int addrSize = env->GetArrayLength(addressArray);
- // get the address bytes
- jbyte *addr = env->GetByteArrayElements(addressArray, NULL);
+ unsigned int addrSize = env->GetArrayLength(remoteAddressArray);
+
+
+ sockaddr_storage localAddress = {};
+
+ if(localAddrObj == NULL)
+ {
+ localAddress = ZT_SOCKADDR_NULL;
+ }
+ else
+ {
+ int localPort = env->CallIntMethod(in_localAddress, inetSock_getPort);
+ jbyteArray localAddressArray = (jbyteArray)env->CallObjectMethod(localAddrObj, getAddressMethod);
+ if(localAddressArray != NULL)
+ {
+
+ unsigned int localAddrSize = env->GetArrayLength(localAddressArray);
+ jbyte *addr = (jbyte*)env->GetPrimitiveArrayCritical(localAddressArray, NULL);
+ if(localAddrSize == 16)
+ {
+ sockaddr_in6 ipv6 = {};
+ ipv6.sin6_family = AF_INET6;
+ ipv6.sin6_port = htons(localPort);
+ memcpy(ipv6.sin6_addr.s6_addr, addr, 16);
+ memcpy(&localAddress, &ipv6, sizeof(sockaddr_in6));
+ }
+ else if(localAddrSize)
+ {
+ // IPV4 address
+ sockaddr_in ipv4 = {};
+ ipv4.sin_family = AF_INET;
+ ipv4.sin_port = htons(localPort);
+ memcpy(&ipv4.sin_addr, addr, 4);
+ memcpy(&localAddress, &ipv4, sizeof(sockaddr_in));
+ }
+ else
+ {
+ localAddress = ZT_SOCKADDR_NULL;
+ }
+ env->ReleasePrimitiveArrayCritical(localAddressArray, addr, 0);
+ }
+ }
+ // get the address bytes
+ jbyte *addr = (jbyte*)env->GetPrimitiveArrayCritical(remoteAddressArray, NULL);
sockaddr_storage remoteAddress = {};
if(addrSize == 16)
@@ -816,7 +883,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
// IPV6 address
sockaddr_in6 ipv6 = {};
ipv6.sin6_family = AF_INET6;
- ipv6.sin6_port = htons(port);
+ ipv6.sin6_port = htons(remotePort);
memcpy(ipv6.sin6_addr.s6_addr, addr, 16);
memcpy(&remoteAddress, &ipv6, sizeof(sockaddr_in6));
}
@@ -825,37 +892,50 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket(
// IPV4 address
sockaddr_in ipv4 = {};
ipv4.sin_family = AF_INET;
- ipv4.sin_port = htons(port);
+ ipv4.sin_port = htons(remotePort);
memcpy(&ipv4.sin_addr, addr, 4);
memcpy(&remoteAddress, &ipv4, sizeof(sockaddr_in));
}
else
{
+ LOGE("Unknown IP version");
// unknown address type
- env->ReleaseByteArrayElements(addressArray, addr, 0);
+ env->ReleasePrimitiveArrayCritical(remoteAddressArray, addr, 0);
return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
}
-
+ env->ReleasePrimitiveArrayCritical(remoteAddressArray, addr, 0);
unsigned int packetLength = env->GetArrayLength(in_packetData);
- jbyte *packetData = env->GetByteArrayElements(in_packetData, NULL);
+ if(packetLength == 0)
+ {
+ LOGE("Empty packet?!?");
+ return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL);
+ }
+ void *packetData = env->GetPrimitiveArrayCritical(in_packetData, NULL);
+ void *localData = malloc(packetLength);
+ memcpy(localData, packetData, packetLength);
+ env->ReleasePrimitiveArrayCritical(in_packetData, packetData, 0);
uint64_t nextBackgroundTaskDeadline = 0;
ZT_ResultCode rc = ZT_Node_processWirePacket(
node,
now,
+ &localAddress,
&remoteAddress,
- packetData,
+ localData,
packetLength,
&nextBackgroundTaskDeadline);
+ if(rc != ZT_RESULT_OK)
+ {
+ LOGE("ZT_Node_processWirePacket returned: %d", rc);
+ }
- jlong *outDeadline = env->GetLongArrayElements(out_nextBackgroundTaskDeadline, NULL);
- outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
- env->ReleaseLongArrayElements(out_nextBackgroundTaskDeadline, outDeadline, 0);
+ free(localData);
- env->ReleaseByteArrayElements(addressArray, addr, 0);
- env->ReleaseByteArrayElements(in_packetData, packetData, 0);
+ jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
+ outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
+ env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
return createResultObject(env, rc);
}
@@ -890,9 +970,9 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processBackgroundTasks(
ZT_ResultCode rc = ZT_Node_processBackgroundTasks(node, now, &nextBackgroundTaskDeadline);
- jlong *outDeadline = env->GetLongArrayElements(out_nextBackgroundTaskDeadline, NULL);
+ jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL);
outDeadline[0] = (jlong)nextBackgroundTaskDeadline;
- env->ReleaseLongArrayElements(out_nextBackgroundTaskDeadline, outDeadline, 0);
+ env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0);
return createResultObject(env, rc);
}
@@ -1043,13 +1123,13 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_status
jmethodID nodeStatusConstructor = NULL;
// create a com.zerotier.sdk.NodeStatus object
- nodeStatusClass = cache.findClass("com/zerotier/sdk/NodeStatus");
+ nodeStatusClass = lookup.findClass("com/zerotier/sdk/NodeStatus");
if(nodeStatusClass == NULL)
{
return NULL;
}
- nodeStatusConstructor = cache.findMethod(
+ nodeStatusConstructor = lookup.findMethod(
nodeStatusClass, "<init>", "()V");
if(nodeStatusConstructor == NULL)
{
@@ -1070,25 +1150,25 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_status
jfieldID secretIdentityField = NULL;
jfieldID onlineField = NULL;
- addressField = cache.findField(nodeStatusClass, "address", "J");
+ addressField = lookup.findField(nodeStatusClass, "address", "J");
if(addressField == NULL)
{
return NULL;
}
- publicIdentityField = cache.findField(nodeStatusClass, "publicIdentity", "Ljava/lang/String;");
+ publicIdentityField = lookup.findField(nodeStatusClass, "publicIdentity", "Ljava/lang/String;");
if(publicIdentityField == NULL)
{
return NULL;
}
- secretIdentityField = cache.findField(nodeStatusClass, "secretIdentity", "Ljava/lang/String;");
+ secretIdentityField = lookup.findField(nodeStatusClass, "secretIdentity", "Ljava/lang/String;");
if(secretIdentityField == NULL)
{
return NULL;
}
- onlineField = cache.findField(nodeStatusClass, "online", "Z");
+ onlineField = lookup.findField(nodeStatusClass, "online", "Z");
if(onlineField == NULL)
{
return NULL;
@@ -1191,7 +1271,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers(
return NULL;
}
- jclass peerClass = cache.findClass("com/zerotier/sdk/Peer");
+ jclass peerClass = lookup.findClass("com/zerotier/sdk/Peer");
if(env->ExceptionCheck() || peerClass == NULL)
{
LOGE("Error finding Peer class");
@@ -1249,7 +1329,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks(
return NULL;
}
- jclass vnetConfigClass = cache.findClass("com/zerotier/sdk/VirtualNetworkConfig");
+ jclass vnetConfigClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfig");
if(env->ExceptionCheck() || vnetConfigClass == NULL)
{
LOGE("Error finding VirtualNetworkConfig class");
diff --git a/java/jni/com_zerotierone_sdk_Node.h b/java/jni/com_zerotierone_sdk_Node.h
index b2e3ed2a..7c1011ab 100644
--- a/java/jni/com_zerotierone_sdk_Node.h
+++ b/java/jni/com_zerotierone_sdk_Node.h
@@ -34,10 +34,10 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame
/*
* Class: com_zerotier_sdk_Node
* Method: processWirePacket
- * Signature: (JJLjava/net/InetSockAddress;[B[J)Lcom/zerotier/sdk/ResultCode;
+ * Signature: (JJLjava/net/InetSockAddress;Ljava/net/InetSockAddress;[B[J)Lcom/zerotier/sdk/ResultCode;
*/
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket
- (JNIEnv *, jobject, jlong, jlong, jobject, jbyteArray, jlongArray);
+ (JNIEnv *, jobject, jlong, jlong, jobject, jobject, jbyteArray, jlongArray);
/*
* Class: com_zerotier_sdk_Node
diff --git a/java/src/com/zerotier/one/AndroidFileProvider.java b/java/src/com/zerotier/one/AndroidFileProvider.java
deleted file mode 100644
index 0988f9df..00000000
--- a/java/src/com/zerotier/one/AndroidFileProvider.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.zerotier.one;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import android.content.Context;
-import android.util.Log;
-
-public class AndroidFileProvider implements DataStoreFileProvider {
- private static final String TAG = "AndroidFileProvider";
-
- Context _ctx;
-
- public AndroidFileProvider(Context ctx) {
- this._ctx = ctx;
- }
-
- @Override
- public FileInputStream getInputFileStream(String name)
- throws FileNotFoundException {
- Log.d(TAG, "Returning FileInputStream for: " + name);
- return _ctx.openFileInput(name);
- }
-
- @Override
- public FileOutputStream getOutputFileStream(String name)
- throws FileNotFoundException {
- Log.d(TAG, "Returning FileOutputStream for: " + name);
- return _ctx.openFileOutput(name, Context.MODE_PRIVATE);
- }
-
- @Override
- public void deleteFile(String name) throws IOException {
- boolean success = _ctx.deleteFile(name);
- if(!success)
- {
- throw new IOException("Unable to delete file.");
- }
- }
-
-}
diff --git a/java/src/com/zerotier/one/DataStore.java b/java/src/com/zerotier/one/DataStore.java
deleted file mode 100644
index d15b2d3d..00000000
--- a/java/src/com/zerotier/one/DataStore.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.zerotier.one;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import com.zerotier.sdk.DataStoreGetListener;
-import com.zerotier.sdk.DataStorePutListener;
-
-public class DataStore implements DataStoreGetListener, DataStorePutListener {
-
- private DataStoreFileProvider _provider;
-
- public DataStore(DataStoreFileProvider provider) {
- this._provider = provider;
- }
-
- @Override
- public int onDataStorePut(String name, byte[] buffer, boolean secure) {
- System.out.println("Writing File: " + name);
- try {
- FileOutputStream fos = _provider.getOutputFileStream(name);
- fos.write(buffer);
- fos.close();
- return 0;
- } catch (FileNotFoundException fnf) {
- fnf.printStackTrace();
- return -1;
- } catch (IOException io) {
- io.printStackTrace();
- return -2;
- }
- }
-
- @Override
- public int onDelete(String name) {
- System.out.println("Deleting File: " + name);
- try {
- _provider.deleteFile(name);
- return 0;
- } catch (IOException ex) {
- ex.printStackTrace();
- return -1;
- }
- }
-
- @Override
- public long onDataStoreGet(String name, byte[] out_buffer,
- long bufferIndex, long[] out_objectSize) {
- System.out.println("Reading File: " + name);
- try {
- FileInputStream fin = _provider.getInputFileStream(name);
- out_objectSize[0] = fin.getChannel().size();
- if(bufferIndex > 0)
- {
- fin.skip(bufferIndex);
- }
- int read = fin.read(out_buffer);
- fin.close();
- return read;
- } catch (FileNotFoundException fnf) {
- // Can't read a file that doesn't exist!
- out_objectSize[0] = 0;
- return 0;
- } catch (IOException io) {
- io.printStackTrace();
- return -2;
- }
- }
-
-
-}
diff --git a/java/src/com/zerotier/one/DataStoreFileProvider.java b/java/src/com/zerotier/one/DataStoreFileProvider.java
deleted file mode 100644
index ffe078eb..00000000
--- a/java/src/com/zerotier/one/DataStoreFileProvider.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.zerotier.one;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-public interface DataStoreFileProvider {
- FileInputStream getInputFileStream(String name) throws FileNotFoundException;
- FileOutputStream getOutputFileStream(String name) throws FileNotFoundException;
- void deleteFile(String name) throws IOException;
-}
diff --git a/java/src/com/zerotier/one/JavaFileProvider.java b/java/src/com/zerotier/one/JavaFileProvider.java
deleted file mode 100644
index 41889e2f..00000000
--- a/java/src/com/zerotier/one/JavaFileProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.zerotier.one;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-public class JavaFileProvider implements DataStoreFileProvider {
- private String _path;
-
- public JavaFileProvider(String path) {
- this._path = path;
- }
-
- @Override
- public FileInputStream getInputFileStream(String name)
- throws FileNotFoundException {
- File f = new File(_path + File.separator + name);
- return new FileInputStream(f);
- }
-
- @Override
- public FileOutputStream getOutputFileStream(String name)
- throws FileNotFoundException {
- File f = new File(_path + File.separator + name);
- if(!f.exists())
- {
- try {
- f.createNewFile();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return new FileOutputStream(f);
- }
-
- @Override
- public void deleteFile(String name) throws IOException {
- File f = new File(_path + File.separator + name);
- boolean success = f.delete();
- if(!success) {
- throw new IOException("Unable to delete file: " + _path + File.pathSeparator + name);
- }
- }
-}
diff --git a/java/src/com/zerotier/one/OneService.java b/java/src/com/zerotier/one/OneService.java
deleted file mode 100644
index 1d3e34c8..00000000
--- a/java/src/com/zerotier/one/OneService.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-
-package com.zerotier.one;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-
-import com.zerotier.sdk.Event;
-import com.zerotier.sdk.EventListener;
-import com.zerotier.sdk.Node;
-import com.zerotier.sdk.PacketSender;
-import com.zerotier.sdk.ResultCode;
-import com.zerotier.sdk.Version;
-import com.zerotier.sdk.VirtualNetworkConfig;
-import com.zerotier.sdk.VirtualNetworkConfigListener;
-import com.zerotier.sdk.VirtualNetworkConfigOperation;
-import com.zerotier.sdk.VirtualNetworkFrameListener;
-
-public class OneService extends Thread implements Runnable, PacketSender,
- EventListener, VirtualNetworkConfigListener,
- VirtualNetworkFrameListener {
- private Node _node;
- private int _port;
-
- private DatagramSocket _udpSocket;
- private ServerSocket _tcpSocket;
- private DataStore _ds;
- private long _nextBackgroundTaskDeadline = 0;
-
- private final Thread _udpReceiveThread = new Thread() {
- @Override
- public void run() {
- try {
- long[] bgtask = new long[1];
- byte[] buffer = new byte[16384];
- while(true) {
-
- bgtask[0] = 0;
- DatagramPacket p = new DatagramPacket(buffer, buffer.length);
-
- try {
- _udpSocket.receive(p);
- if(p.getLength() > 0)
- {
- System.out.println("Got Data From: " + p.getAddress().toString() +":" + p.getPort());
-
- _node.processWirePacket(System.currentTimeMillis(), new InetSocketAddress(p.getAddress(), p.getPort()), p.getData(), bgtask);
- _nextBackgroundTaskDeadline = bgtask[0];
- }
- } catch (SocketTimeoutException e) {}
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- };
-
-
- public OneService(DataStoreFileProvider prov, int port) {
- this._port = port;
- this._ds = new DataStore(prov);
-
- try {
- _udpSocket = new DatagramSocket(_port);
- _udpSocket.setSoTimeout(100);
- _tcpSocket = new ServerSocket();
- _tcpSocket.bind(new InetSocketAddress("127.0.0.1", _port));
- } catch (SocketException e) {
- e.printStackTrace();
- return;
- } catch (IOException e) {
- e.printStackTrace();
- return;
- }
-
- _udpReceiveThread.start();
-
- _node = new Node(
- System.currentTimeMillis(),
- _ds,
- _ds,
- this,
- this,
- this,
- this);
- }
-
- @Override
- public void run() {
- if(_node == null)
- return;
-
- while(true) {
- try {
-
- long dl = _nextBackgroundTaskDeadline;
- long now = System.currentTimeMillis();
-
- if (dl <= now) {
- long[] returnDeadline = {0};
- ResultCode rc = _node.processBackgroundTasks(now, returnDeadline);
- _nextBackgroundTaskDeadline = returnDeadline[0];
-
- if(rc != ResultCode.RESULT_OK) {
- System.out.println(rc.toString());
- }
- }
-
- long delay = (dl > now) ? (dl - now) : 100;
- Thread.sleep(delay);
-
- } catch (Exception ex) {
- System.out.println("Exception in run loop: " + ex.getMessage());
- ex.printStackTrace();
- }
- }
- }
-
- @Override
- public int onSendPacketRequested(InetSocketAddress addr, byte[] packetData) {
- System.out.println("onSendPacketRequested to: " + addr.getHostString() +":"+ addr.getPort() + " ");
-
- if(_udpSocket == null)
- return -1;
- try {
- DatagramPacket p = new DatagramPacket(packetData, packetData.length, addr);
- _udpSocket.send(p);
- System.out.println("Sent");
- } catch (Exception e) {
- System.out.println("Error sending datagram: " + e.getMessage());
- return -1;
- }
- return 0;
- }
-
- @Override
- public void onVirtualNetworkFrame(long nwid, long srcMac, long destMac,
- long etherType, long vlanId, byte[] frameData) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public int onNetworkConfigurationUpdated(long nwid,
- VirtualNetworkConfigOperation op, VirtualNetworkConfig config) {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public void onEvent(Event event) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void onNetworkError(Event event, InetSocketAddress source) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void onOutOfDate(Version newVersion) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void onTrace(String message) {
- // TODO Auto-generated method stub
-
- }
-}
diff --git a/java/src/com/zerotier/sdk/Event.java b/java/src/com/zerotier/sdk/Event.java
index 436b1b22..22d350e1 100644
--- a/java/src/com/zerotier/sdk/Event.java
+++ b/java/src/com/zerotier/sdk/Event.java
@@ -86,31 +86,6 @@ public enum Event {
* umbrellas prevent rain and smoke detectors prevent fires. They do, right?</p>
*/
EVENT_FATAL_ERROR_IDENTITY_COLLISION,
-
- /**
- * A more recent version was observed on the network
- *
- * <p>Right now this is only triggered if a hub or rootserver reports a
- * more recent version, and only once. It can be used to trigger a
- * software update check.</p>
- *
- * <p>Meta-data: {@link Version}, more recent version number</p>
- */
- EVENT_SAW_MORE_RECENT_VERSION,
-
- /**
- * A packet failed authentication
- *
- * <p>Meta-data: {@link InetSocketAddress} containing origin address of packet</p>
- */
- EVENT_AUTHENTICATION_FAILURE,
-
- /**
- * A received packet was not valid
- *
- * <p>Meta-data: {@link InetSocketAddress} containing origin address of packet</p>
- */
- EVENT_INVALID_PACKET,
/**
* Trace (debugging) message
diff --git a/java/src/com/zerotier/sdk/EventListener.java b/java/src/com/zerotier/sdk/EventListener.java
index 078023d9..91050aaa 100644
--- a/java/src/com/zerotier/sdk/EventListener.java
+++ b/java/src/com/zerotier/sdk/EventListener.java
@@ -42,21 +42,6 @@ public interface EventListener {
public void onEvent(Event event);
/**
- * Callback for network error events: {@link Event.EVENT_AUTHENTICATION_FAILUER}, {link Event.EVENT_INVALID_PACKET}
- *
- * @param event {@link Event} enum
- * @param source {@link InetSocketAddress} containing the origin address of the packet
- */
- public void onNetworkError(Event event, InetSocketAddress source);
-
- /**
- * Callback when the node detects that it's out of date.
- *
- * @param newVersion {@link Version} object with the latest version of ZeroTier One
- */
- public void onOutOfDate(Version newVersion);
-
- /**
* Trace messages
*
* <p>These events are only generated if the underlying ZeroTierOne SDK is a TRACE-enabled build.</p>
diff --git a/java/src/com/zerotier/sdk/MulticastGroup.java b/java/src/com/zerotier/sdk/MulticastGroup.java
index 5c4df87a..68114424 100644
--- a/java/src/com/zerotier/sdk/MulticastGroup.java
+++ b/java/src/com/zerotier/sdk/MulticastGroup.java
@@ -33,6 +33,10 @@ public final class MulticastGroup {
private long mac;
private long adi;
+ public boolean equals(MulticastGroup other) {
+ return mac == other.mac && adi == other.adi;
+ }
+
/**
* MAC address (least significant 48 bits)
*/
diff --git a/java/src/com/zerotier/sdk/Node.java b/java/src/com/zerotier/sdk/Node.java
index e5b12697..4bc6e184 100644
--- a/java/src/com/zerotier/sdk/Node.java
+++ b/java/src/com/zerotier/sdk/Node.java
@@ -169,11 +169,12 @@ public class Node {
*/
public ResultCode processWirePacket(
long now,
+ InetSocketAddress localAddress,
InetSocketAddress remoteAddress,
byte[] packetData,
long[] nextBackgroundTaskDeadline) {
return processWirePacket(
- nodeId, now, remoteAddress, packetData,
+ nodeId, now, localAddress, remoteAddress, packetData,
nextBackgroundTaskDeadline);
}
@@ -393,6 +394,7 @@ public class Node {
private native ResultCode processWirePacket(
long nodeId,
long now,
+ InetSocketAddress localAddress,
InetSocketAddress remoteAddress,
byte[] packetData,
long[] nextBackgroundTaskDeadline);
diff --git a/java/src/com/zerotier/sdk/PacketSender.java b/java/src/com/zerotier/sdk/PacketSender.java
index 5302f5ce..22893ec7 100644
--- a/java/src/com/zerotier/sdk/PacketSender.java
+++ b/java/src/com/zerotier/sdk/PacketSender.java
@@ -37,11 +37,14 @@ public interface PacketSender {
* on failure. Note that success does not (of course) guarantee packet
* delivery. It only means that the packet appears to have been sent.</p>
*
- * @param addr {@link InetSocketAddress} to send to
+ * @param localAddr {@link InetSocketAddress} to send from. Set to null if not specified.
+ * @param remoteAddr {@link InetSocketAddress} to send to
* @param packetData data to send
* @return 0 on success, any error code on failure.
*/
public int onSendPacketRequested(
- InetSocketAddress addr,
- byte[] packetData);
+ InetSocketAddress localAddr,
+ InetSocketAddress remoteAddr,
+ byte[] packetData,
+ int ttl);
}
diff --git a/java/src/com/zerotier/sdk/PeerRole.java b/java/src/com/zerotier/sdk/PeerRole.java
index 7a5156e1..d7d55f05 100644
--- a/java/src/com/zerotier/sdk/PeerRole.java
+++ b/java/src/com/zerotier/sdk/PeerRole.java
@@ -34,12 +34,12 @@ public enum PeerRole {
PEER_ROLE_LEAF,
/**
- * Locally federated hub
+ * relay node
*/
- PEER_ROLE_HUB,
+ PEER_ROLE_RELAY,
/**
- * planetary rootserver
+ * root server
*/
- PEER_ROLE_ROOTSERVER
+ PEER_ROLE_ROOT
} \ No newline at end of file
diff --git a/java/src/com/zerotier/sdk/VirtualNetworkConfig.java b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java
index 78ac9da5..9816180b 100644
--- a/java/src/com/zerotier/sdk/VirtualNetworkConfig.java
+++ b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java
@@ -27,11 +27,13 @@
package com.zerotier.sdk;
+import java.lang.Comparable;
+import java.lang.Override;
import java.lang.String;
import java.util.ArrayList;
import java.net.InetSocketAddress;
-public final class VirtualNetworkConfig {
+public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConfig> {
public static final int MAX_MULTICAST_SUBSCRIPTIONS = 4096;
public static final int ZT_MAX_ZT_ASSIGNED_ADDRESSES = 16;
@@ -54,6 +56,40 @@ public final class VirtualNetworkConfig {
}
+ public boolean equals(VirtualNetworkConfig cfg) {
+ boolean aaEqual = true;
+ if(assignedAddresses.length == cfg.assignedAddresses.length) {
+ for(int i = 0; i < assignedAddresses.length; ++i) {
+ if(!assignedAddresses[i].equals(cfg.assignedAddresses[i])) {
+ return false;
+ }
+ }
+ } else {
+ aaEqual = false;
+ }
+
+ return nwid == cfg.nwid &&
+ mac == cfg.mac &&
+ name.equals(cfg.name) &&
+ status.equals(cfg.status) &&
+ type.equals(cfg.type) &&
+ mtu == cfg.mtu &&
+ dhcp == cfg.dhcp &&
+ bridge == cfg.bridge &&
+ broadcastEnabled == cfg.broadcastEnabled &&
+ portError == cfg.portError &&
+ enabled == cfg.enabled &&
+ aaEqual;
+ }
+
+ public int compareTo(VirtualNetworkConfig cfg) {
+ if(cfg.nwid == this.nwid) {
+ return 0;
+ } else {
+ return this.nwid > cfg.nwid ? 1 : -1;
+ }
+ }
+
/**
* 64-bit ZeroTier network ID
*/
diff --git a/make-freebsd.mk b/make-freebsd.mk
index 1322dd53..022540d2 100644
--- a/make-freebsd.mk
+++ b/make-freebsd.mk
@@ -13,6 +13,11 @@ ifeq ($(ZT_OFFICIAL_RELEASE),1)
DEFS+=-DZT_OFFICIAL_RELEASE
endif
+# Build with ZT_ENABLE_CLUSTER=1 to build with cluster support
+ifeq ($(ZT_ENABLE_CLUSTER),1)
+ DEFS+=-DZT_ENABLE_CLUSTER
+endif
+
# "make debug" is a shortcut for this
ifeq ($(ZT_DEBUG),1)
DEFS+=-DZT_TRACE
diff --git a/make-linux.mk b/make-linux.mk
index 6d48d3df..51b8bc96 100644
--- a/make-linux.mk
+++ b/make-linux.mk
@@ -26,11 +26,11 @@ ifeq ($(origin CXX),default)
CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi)
endif
-UNAME_M=$(shell uname -m)
+#UNAME_M=$(shell $(CC) -dumpmachine | cut -d '-' -f 1)
INCLUDES=-Iext/lwip/src/include -Iext/lwip/src/include/ipv4 -Iext/lwip/src/include/ipv6
-DEFS=-DZT_ENABLE_NETCON #-DVERBOSE
-CXXFLAGS+=-Wc++11-compat-deprecated-writable-strings -Wformat
+DEFS=-DZT_ENABLE_NETCON
+#CXXFLAGS+=-Wc++11-compat-deprecated-writable-strings -Wformat
LDLIBS?=
include objects.mk
@@ -44,31 +44,20 @@ endif
ifeq ($(ZT_USE_MINIUPNPC),1)
DEFS+=-DZT_USE_MINIUPNPC
-ifeq ($(UNAME_M),armv6l)
- MINIUPNPC_LIB=ext/bin/miniupnpc/linux-arm32/libminiupnpc.a
-endif
-ifeq ($(UNAME_M),armv7l)
- MINIUPNPC_LIB=ext/bin/miniupnpc/linux-arm32/libminiupnpc.a
-endif
-ifeq ($(UNAME_M),x86_64)
- MINIUPNPC_LIB=ext/bin/miniupnpc/linux-x64/libminiupnpc.a
-endif
-ifeq ($(UNAME_M),i386)
- MINIUPNPC_LIB=ext/bin/miniupnpc/linux-x86/libminiupnpc.a
-endif
-ifeq ($(UNAME_M),i686)
- MINIUPNPC_LIB=ext/bin/miniupnpc/linux-x86/libminiupnpc.a
-endif
- MINIUPNPC_LIB?=-lminiupnpc
- LDLIBS+=$(MINIUPNPC_LIB)
+ LDLIBS+=ext/miniupnpc/libminiupnpc.a
OBJS+=osdep/UPNPClient.o
endif
# Build with ZT_ENABLE_NETWORK_CONTROLLER=1 to build with the Sqlite network controller
ifeq ($(ZT_ENABLE_NETWORK_CONTROLLER),1)
- DEFS+=-DZT_ENABLE_NETWORK_CONTROLLER
- LDLIBS+=-L/usr/local/lib -lsqlite3
- OBJS+=controller/SqliteNetworkController.o
+ DEFS+=-DZT_ENABLE_NETWORK_CONTROLLER
+ LDLIBS+=-L/usr/local/lib -lsqlite3
+ OBJS+=controller/SqliteNetworkController.o
+endif
+
+# Build with ZT_ENABLE_CLUSTER=1 to build with cluster support
+ifeq ($(ZT_ENABLE_CLUSTER),1)
+ DEFS+=-DZT_ENABLE_CLUSTER
endif
# "make debug" is a shortcut for this
@@ -90,6 +79,10 @@ else
STRIP=strip --strip-all
endif
+ifeq ($(ZT_TRACE),1)
+ DEFS+=-DZT_TRACE
+endif
+
# Uncomment for gprof profile build
#CFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS)
#CXXFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS)
@@ -99,6 +92,9 @@ endif
all: one
one: $(OBJS) one.o
+ifeq ($(ZT_USE_MINIUPNPC),1)
+ cd ext/miniupnpc ; make clean ; make 'CFLAGS=-O2 -fstack-protector -fPIE -fno-common -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600' -j 2 libminiupnpc.a
+endif
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) one.o $(LDLIBS)
$(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool
@@ -112,14 +108,14 @@ installer: one FORCE
./ext/installfiles/linux/buildinstaller.sh
clean:
- rm -rf *.o
- find netcon/ -name "*.1.0" -type f -delete
- find netcon/ -name "*.so" -type f -delete
- find netcon/ -name "zerotier-one" -type f -delete
- find netcon/ -name "zerotier-cli" -type f -delete
+ find ./ -type f -name '*.o' -delete
+ find netcon/ -type f -name '*.so' -delete
+ find netcon/ -type f -name '*.1.0' -delete
+ find netcon/ -type f -name 'zerotier-one' -delete
+ find netcon/ -type f -name 'zerotier-cli' -delete
find netcon/docker-test -name "zerotier-intercept" -type f -delete
- rm -rf netcon/*.o netcon/*.so netcon/*.1.0
- rm -rf node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm
+ rm -rf zerotier-one zerotier-idtool zerotier-cli zerotier-selftest zerotier-netcon build-* ZeroTierOneInstaller-* *.deb *.rpm *.pkg *.tgz
+ cd ext/miniupnpc ; make clean
debug: FORCE
make ZT_DEBUG=1 one
diff --git a/make-mac.mk b/make-mac.mk
index 6daa6aa0..d30fc5bd 100644
--- a/make-mac.mk
+++ b/make-mac.mk
@@ -13,15 +13,15 @@ ARCH_FLAGS=-arch x86_64
include objects.mk
OBJS+=osdep/OSXEthernetTap.o
-# Comment out to disable building against shipped libminiupnpc binary for Mac
-ZT_USE_MINIUPNPC?=1
-
# Disable codesign since open source users will not have ZeroTier's certs
CODESIGN=echo
PRODUCTSIGN=echo
CODESIGN_APP_CERT=
CODESIGN_INSTALLER_CERT=
+# Build with libminiupnpc by default for Mac
+ZT_USE_MINIUPNPC?=1
+
# For internal use only -- signs everything with ZeroTier's developer cert
ifeq ($(ZT_OFFICIAL_RELEASE),1)
DEFS+=-DZT_OFFICIAL_RELEASE -DZT_AUTO_UPDATE
@@ -32,13 +32,18 @@ ifeq ($(ZT_OFFICIAL_RELEASE),1)
CODESIGN_INSTALLER_CERT="Developer ID Installer: ZeroTier Networks LLC (8ZD9JUCZ4V)"
endif
+# Build with ZT_ENABLE_CLUSTER=1 to build with cluster support
+ifeq ($(ZT_ENABLE_CLUSTER),1)
+ DEFS+=-DZT_ENABLE_CLUSTER
+endif
+
ifeq ($(ZT_AUTO_UPDATE),1)
DEFS+=-DZT_AUTO_UPDATE
endif
ifeq ($(ZT_USE_MINIUPNPC),1)
DEFS+=-DZT_USE_MINIUPNPC
- LIBS+=ext/bin/miniupnpc/mac-x64/libminiupnpc.a
+ LIBS+=ext/miniupnpc/libminiupnpc.a
OBJS+=osdep/UPNPClient.o
endif
@@ -68,6 +73,9 @@ CXXFLAGS=$(CFLAGS) -fno-rtti
all: one
one: $(OBJS) one.o
+ifeq ($(ZT_USE_MINIUPNPC),1)
+ cd ext/miniupnpc ; make clean ; make 'CFLAGS=-D_DARWIN_C_SOURCE -O2 -fstack-protector -fPIE -flto -pthread -mmacosx-version-min=10.7 -fno-common -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE' -j 2 libminiupnpc.a
+endif
$(CXX) $(CXXFLAGS) -o zerotier-one $(OBJS) one.o $(LIBS)
$(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool
@@ -93,7 +101,8 @@ official: FORCE
make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg
clean:
- rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-*
+ rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-* mkworld
+ cd ext/miniupnpc ; make clean
# For those building from source -- installs signed binary tap driver in system ZT home
install-mac-tap: FORCE
diff --git a/node/AntiRecursion.hpp b/node/AntiRecursion.hpp
index c5aa92d8..4d9df465 100644
--- a/node/AntiRecursion.hpp
+++ b/node/AntiRecursion.hpp
@@ -35,30 +35,35 @@
namespace ZeroTier {
-#define ZT_ANTIRECURSION_TAIL_LEN 256
+/**
+ * Size of anti-recursion history
+ */
+#define ZT_ANTIRECURSION_HISTORY_SIZE 16
/**
* Filter to prevent recursion (ZeroTier-over-ZeroTier)
*
* This works by logging ZeroTier packets that we send. It's then invoked
- * again against packets read from local Ethernet taps. If the last N
+ * again against packets read from local Ethernet taps. If the last 32
* bytes representing the ZeroTier packet match in the tap frame, then
* the frame is a re-injection of a frame that we sent and is rejected.
*
* This means that ZeroTier packets simply will not traverse ZeroTier
* networks, which would cause all sorts of weird problems.
*
- * NOTE: this is applied to low-level packets before they are sent to
- * SocketManager and/or sockets, not to fully assembled packets before
- * (possible) fragmentation.
+ * This is highly optimized code since it's checked for every packet.
*/
class AntiRecursion
{
public:
AntiRecursion()
- throw()
{
- memset(_history,0,sizeof(_history));
+ for(int i=0;i<ZT_ANTIRECURSION_HISTORY_SIZE;++i) {
+ _history[i].tail[0] = 0;
+ _history[i].tail[1] = 0;
+ _history[i].tail[2] = 0;
+ _history[i].tail[3] = 0;
+ }
_ptr = 0;
}
@@ -68,13 +73,20 @@ public:
* @param data ZT packet data
* @param len Length of packet
*/
- inline void logOutgoingZT(const void *data,unsigned int len)
- throw()
+ inline void logOutgoingZT(const void *const data,const unsigned int len)
{
- ArItem *i = &(_history[_ptr++ % ZT_ANTIRECURSION_HISTORY_SIZE]);
- const unsigned int tl = (len > ZT_ANTIRECURSION_TAIL_LEN) ? ZT_ANTIRECURSION_TAIL_LEN : len;
- memcpy(i->tail,((const unsigned char *)data) + (len - tl),tl);
- i->len = tl;
+ if (len < 32)
+ return;
+#ifdef ZT_NO_TYPE_PUNNING
+ memcpy(_history[++_ptr % ZT_ANTIRECURSION_HISTORY_SIZE].tail,reinterpret_cast<const uint8_t *>(data) + (len - 32),32);
+#else
+ uint64_t *t = _history[++_ptr % ZT_ANTIRECURSION_HISTORY_SIZE].tail;
+ const uint64_t *p = reinterpret_cast<const uint64_t *>(reinterpret_cast<const uint8_t *>(data) + (len - 32));
+ *(t++) = *(p++);
+ *(t++) = *(p++);
+ *(t++) = *(p++);
+ *t = *p;
+#endif
}
/**
@@ -84,25 +96,36 @@ public:
* @param len Length of frame
* @return True if frame is OK to be passed, false if it's a ZT frame that we sent
*/
- inline bool checkEthernetFrame(const void *data,unsigned int len)
- throw()
+ inline bool checkEthernetFrame(const void *const data,const unsigned int len) const
{
- for(unsigned int h=0;h<ZT_ANTIRECURSION_HISTORY_SIZE;++h) {
- ArItem *i = &(_history[h]);
- if ((i->len > 0)&&(len >= i->len)&&(!memcmp(((const unsigned char *)data) + (len - i->len),i->tail,i->len)))
+ if (len < 32)
+ return true;
+ const uint8_t *const pp = reinterpret_cast<const uint8_t *>(data) + (len - 32);
+ const _ArItem *i = _history;
+ const _ArItem *const end = i + ZT_ANTIRECURSION_HISTORY_SIZE;
+ while (i != end) {
+#ifdef ZT_NO_TYPE_PUNNING
+ if (!memcmp(pp,i->tail,32))
return false;
+#else
+ const uint64_t *t = i->tail;
+ const uint64_t *p = reinterpret_cast<const uint64_t *>(pp);
+ uint64_t bits = *(t++) ^ *(p++);
+ bits |= *(t++) ^ *(p++);
+ bits |= *(t++) ^ *(p++);
+ bits |= *t ^ *p;
+ if (!bits)
+ return false;
+#endif
+ ++i;
}
return true;
}
private:
- struct ArItem
- {
- unsigned char tail[ZT_ANTIRECURSION_TAIL_LEN];
- unsigned int len;
- };
- ArItem _history[ZT_ANTIRECURSION_HISTORY_SIZE];
- volatile unsigned int _ptr;
+ struct _ArItem { uint64_t tail[4]; };
+ _ArItem _history[ZT_ANTIRECURSION_HISTORY_SIZE];
+ volatile unsigned long _ptr;
};
} // namespace ZeroTier
diff --git a/node/BinarySemaphore.hpp b/node/BinarySemaphore.hpp
new file mode 100644
index 00000000..97d0d1c4
--- /dev/null
+++ b/node/BinarySemaphore.hpp
@@ -0,0 +1,106 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_BINARYSEMAPHORE_HPP
+#define ZT_BINARYSEMAPHORE_HPP
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "Constants.hpp"
+#include "NonCopyable.hpp"
+
+#ifdef __WINDOWS__
+
+#include <Windows.h>
+
+namespace ZeroTier {
+
+class BinarySemaphore : NonCopyable
+{
+public:
+ BinarySemaphore() throw() { _sem = CreateSemaphore(NULL,0,1,NULL); }
+ ~BinarySemaphore() { CloseHandle(_sem); }
+ inline void wait() { WaitForSingleObject(_sem,INFINITE); }
+ inline void post() { ReleaseSemaphore(_sem,1,NULL); }
+private:
+ HANDLE _sem;
+};
+
+} // namespace ZeroTier
+
+#else // !__WINDOWS__
+
+#include <pthread.h>
+
+namespace ZeroTier {
+
+class BinarySemaphore : NonCopyable
+{
+public:
+ BinarySemaphore()
+ {
+ pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0);
+ pthread_cond_init(&_cond,(const pthread_condattr_t *)0);
+ _f = false;
+ }
+
+ ~BinarySemaphore()
+ {
+ pthread_cond_destroy(&_cond);
+ pthread_mutex_destroy(&_mh);
+ }
+
+ inline void wait()
+ {
+ pthread_mutex_lock(const_cast <pthread_mutex_t *>(&_mh));
+ while (!_f)
+ pthread_cond_wait(const_cast <pthread_cond_t *>(&_cond),const_cast <pthread_mutex_t *>(&_mh));
+ _f = false;
+ pthread_mutex_unlock(const_cast <pthread_mutex_t *>(&_mh));
+ }
+
+ inline void post()
+ {
+ pthread_mutex_lock(const_cast <pthread_mutex_t *>(&_mh));
+ _f = true;
+ pthread_mutex_unlock(const_cast <pthread_mutex_t *>(&_mh));
+ pthread_cond_signal(const_cast <pthread_cond_t *>(&_cond));
+ }
+
+private:
+ pthread_cond_t _cond;
+ pthread_mutex_t _mh;
+ volatile bool _f;
+};
+
+} // namespace ZeroTier
+
+#endif // !__WINDOWS__
+
+#endif
diff --git a/node/Cluster.cpp b/node/Cluster.cpp
new file mode 100644
index 00000000..fa9a1611
--- /dev/null
+++ b/node/Cluster.cpp
@@ -0,0 +1,913 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifdef ZT_ENABLE_CLUSTER
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <map>
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <list>
+#include <stdexcept>
+
+#include "../version.h"
+
+#include "Cluster.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "MulticastGroup.hpp"
+#include "CertificateOfMembership.hpp"
+#include "Salsa20.hpp"
+#include "Poly1305.hpp"
+#include "Identity.hpp"
+#include "Topology.hpp"
+#include "Packet.hpp"
+#include "Switch.hpp"
+#include "Node.hpp"
+#include "Array.hpp"
+
+namespace ZeroTier {
+
+static inline double _dist3d(int x1,int y1,int z1,int x2,int y2,int z2)
+ throw()
+{
+ double dx = ((double)x2 - (double)x1);
+ double dy = ((double)y2 - (double)y1);
+ double dz = ((double)z2 - (double)z1);
+ return sqrt((dx * dx) + (dy * dy) + (dz * dz));
+}
+
+// An entry in _ClusterSendQueue
+struct _ClusterSendQueueEntry
+{
+ uint64_t timestamp;
+ Address fromPeerAddress;
+ Address toPeerAddress;
+ // if we ever support larger transport MTUs this must be increased
+ unsigned char data[ZT_CLUSTER_SEND_QUEUE_DATA_MAX];
+ unsigned int len;
+ bool unite;
+};
+
+// A multi-index map with entry memory pooling -- this allows our queue to
+// be O(log(N)) and is complex enough that it makes the code a lot cleaner
+// to break it out from Cluster.
+class _ClusterSendQueue
+{
+public:
+ _ClusterSendQueue() :
+ _poolCount(0) {}
+ ~_ClusterSendQueue() {} // memory is automatically freed when _chunks is destroyed
+
+ inline void enqueue(uint64_t now,const Address &from,const Address &to,const void *data,unsigned int len,bool unite)
+ {
+ if (len > ZT_CLUSTER_SEND_QUEUE_DATA_MAX)
+ return;
+
+ Mutex::Lock _l(_lock);
+
+ // Delete oldest queue entry for this sender if this enqueue() would take them over the per-sender limit
+ {
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> >::iterator qi(_bySrc.lower_bound(std::pair<Address,_ClusterSendQueueEntry *>(from,(_ClusterSendQueueEntry *)0)));
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> >::iterator oldest(qi);
+ unsigned long countForSender = 0;
+ while ((qi != _bySrc.end())&&(qi->first == from)) {
+ if (qi->second->timestamp < oldest->second->timestamp)
+ oldest = qi;
+ ++countForSender;
+ ++qi;
+ }
+ if (countForSender >= ZT_CLUSTER_MAX_QUEUE_PER_SENDER) {
+ _byDest.erase(std::pair<Address,_ClusterSendQueueEntry *>(oldest->second->toPeerAddress,oldest->second));
+ _pool[_poolCount++] = oldest->second;
+ _bySrc.erase(oldest);
+ }
+ }
+
+ _ClusterSendQueueEntry *e;
+ if (_poolCount > 0) {
+ e = _pool[--_poolCount];
+ } else {
+ if (_chunks.size() >= ZT_CLUSTER_MAX_QUEUE_CHUNKS)
+ return; // queue is totally full!
+ _chunks.push_back(Array<_ClusterSendQueueEntry,ZT_CLUSTER_QUEUE_CHUNK_SIZE>());
+ e = &(_chunks.back().data[0]);
+ for(unsigned int i=1;i<ZT_CLUSTER_QUEUE_CHUNK_SIZE;++i)
+ _pool[_poolCount++] = &(_chunks.back().data[i]);
+ }
+
+ e->timestamp = now;
+ e->fromPeerAddress = from;
+ e->toPeerAddress = to;
+ memcpy(e->data,data,len);
+ e->len = len;
+ e->unite = unite;
+
+ _bySrc.insert(std::pair<Address,_ClusterSendQueueEntry *>(from,e));
+ _byDest.insert(std::pair<Address,_ClusterSendQueueEntry *>(to,e));
+ }
+
+ inline void expire(uint64_t now)
+ {
+ Mutex::Lock _l(_lock);
+ for(std::set< std::pair<Address,_ClusterSendQueueEntry *> >::iterator qi(_bySrc.begin());qi!=_bySrc.end();) {
+ if ((now - qi->second->timestamp) > ZT_CLUSTER_QUEUE_EXPIRATION) {
+ _byDest.erase(std::pair<Address,_ClusterSendQueueEntry *>(qi->second->toPeerAddress,qi->second));
+ _pool[_poolCount++] = qi->second;
+ _bySrc.erase(qi++);
+ } else ++qi;
+ }
+ }
+
+ /**
+ * Get and dequeue entries for a given destination address
+ *
+ * After use these entries must be returned with returnToPool()!
+ *
+ * @param dest Destination address
+ * @param results Array to fill with results
+ * @param maxResults Size of results[] in pointers
+ * @return Number of actual results returned
+ */
+ inline unsigned int getByDest(const Address &dest,_ClusterSendQueueEntry **results,unsigned int maxResults)
+ {
+ unsigned int count = 0;
+ Mutex::Lock _l(_lock);
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> >::iterator qi(_byDest.lower_bound(std::pair<Address,_ClusterSendQueueEntry *>(dest,(_ClusterSendQueueEntry *)0)));
+ while ((qi != _byDest.end())&&(qi->first == dest)) {
+ _bySrc.erase(std::pair<Address,_ClusterSendQueueEntry *>(qi->second->fromPeerAddress,qi->second));
+ results[count++] = qi->second;
+ if (count == maxResults)
+ break;
+ _byDest.erase(qi++);
+ }
+ return count;
+ }
+
+ /**
+ * Return entries to pool after use
+ *
+ * @param entries Array of entries
+ * @param count Number of entries
+ */
+ inline void returnToPool(_ClusterSendQueueEntry **entries,unsigned int count)
+ {
+ Mutex::Lock _l(_lock);
+ for(unsigned int i=0;i<count;++i)
+ _pool[_poolCount++] = entries[i];
+ }
+
+private:
+ std::list< Array<_ClusterSendQueueEntry,ZT_CLUSTER_QUEUE_CHUNK_SIZE> > _chunks;
+ _ClusterSendQueueEntry *_pool[ZT_CLUSTER_QUEUE_CHUNK_SIZE * ZT_CLUSTER_MAX_QUEUE_CHUNKS];
+ unsigned long _poolCount;
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> > _bySrc;
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> > _byDest;
+ Mutex _lock;
+};
+
+Cluster::Cluster(
+ const RuntimeEnvironment *renv,
+ uint16_t id,
+ const std::vector<InetAddress> &zeroTierPhysicalEndpoints,
+ int32_t x,
+ int32_t y,
+ int32_t z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg) :
+ RR(renv),
+ _sendQueue(new _ClusterSendQueue()),
+ _sendFunction(sendFunction),
+ _sendFunctionArg(sendFunctionArg),
+ _addressToLocationFunction(addressToLocationFunction),
+ _addressToLocationFunctionArg(addressToLocationFunctionArg),
+ _x(x),
+ _y(y),
+ _z(z),
+ _id(id),
+ _zeroTierPhysicalEndpoints(zeroTierPhysicalEndpoints),
+ _members(new _Member[ZT_CLUSTER_MAX_MEMBERS]),
+ _lastFlushed(0),
+ _lastCleanedRemotePeers(0),
+ _lastCleanedQueue(0)
+{
+ uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)];
+
+ // Generate master secret by hashing the secret from our Identity key pair
+ RR->identity.sha512PrivateKey(_masterSecret);
+
+ // Generate our inbound message key, which is the master secret XORed with our ID and hashed twice
+ memcpy(stmp,_masterSecret,sizeof(stmp));
+ stmp[0] ^= Utils::hton(id);
+ SHA512::hash(stmp,stmp,sizeof(stmp));
+ SHA512::hash(stmp,stmp,sizeof(stmp));
+ memcpy(_key,stmp,sizeof(_key));
+ Utils::burn(stmp,sizeof(stmp));
+}
+
+Cluster::~Cluster()
+{
+ Utils::burn(_masterSecret,sizeof(_masterSecret));
+ Utils::burn(_key,sizeof(_key));
+ delete [] _members;
+ delete _sendQueue;
+}
+
+void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len)
+{
+ Buffer<ZT_CLUSTER_MAX_MESSAGE_LENGTH> dmsg;
+ {
+ // FORMAT: <[16] iv><[8] MAC><... data>
+ if ((len < 24)||(len > ZT_CLUSTER_MAX_MESSAGE_LENGTH))
+ return;
+
+ // 16-byte IV: first 8 bytes XORed with key, last 8 bytes used as Salsa20 64-bit IV
+ char keytmp[32];
+ memcpy(keytmp,_key,32);
+ for(int i=0;i<8;++i)
+ keytmp[i] ^= reinterpret_cast<const char *>(msg)[i];
+ Salsa20 s20(keytmp,256,reinterpret_cast<const char *>(msg) + 8);
+ Utils::burn(keytmp,sizeof(keytmp));
+
+ // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
+ char polykey[ZT_POLY1305_KEY_LEN];
+ memset(polykey,0,sizeof(polykey));
+ s20.encrypt12(polykey,polykey,sizeof(polykey));
+
+ // Compute 16-byte MAC
+ char mac[ZT_POLY1305_MAC_LEN];
+ Poly1305::compute(mac,reinterpret_cast<const char *>(msg) + 24,len - 24,polykey);
+
+ // Check first 8 bytes of MAC against 64-bit MAC in stream
+ if (!Utils::secureEq(mac,reinterpret_cast<const char *>(msg) + 16,8))
+ return;
+
+ // Decrypt!
+ dmsg.setSize(len - 24);
+ s20.decrypt12(reinterpret_cast<const char *>(msg) + 24,const_cast<void *>(dmsg.data()),dmsg.size());
+ }
+
+ if (dmsg.size() < 4)
+ return;
+ const uint16_t fromMemberId = dmsg.at<uint16_t>(0);
+ unsigned int ptr = 2;
+ if (fromMemberId == _id) // sanity check: we don't talk to ourselves
+ return;
+ const uint16_t toMemberId = dmsg.at<uint16_t>(ptr);
+ ptr += 2;
+ if (toMemberId != _id) // sanity check: message not for us?
+ return;
+
+ { // make sure sender is actually considered a member
+ Mutex::Lock _l3(_memberIds_m);
+ if (std::find(_memberIds.begin(),_memberIds.end(),fromMemberId) == _memberIds.end())
+ return;
+ }
+
+ try {
+ while (ptr < dmsg.size()) {
+ const unsigned int mlen = dmsg.at<uint16_t>(ptr); ptr += 2;
+ const unsigned int nextPtr = ptr + mlen;
+ if (nextPtr > dmsg.size())
+ break;
+
+ int mtype = -1;
+ try {
+ switch((StateMessageType)(mtype = (int)dmsg[ptr++])) {
+ default:
+ break;
+
+ case CLUSTER_MESSAGE_ALIVE: {
+ _Member &m = _members[fromMemberId];
+ Mutex::Lock mlck(m.lock);
+ ptr += 7; // skip version stuff, not used yet
+ m.x = dmsg.at<int32_t>(ptr); ptr += 4;
+ m.y = dmsg.at<int32_t>(ptr); ptr += 4;
+ m.z = dmsg.at<int32_t>(ptr); ptr += 4;
+ ptr += 8; // skip local clock, not used
+ m.load = dmsg.at<uint64_t>(ptr); ptr += 8;
+ m.peers = dmsg.at<uint64_t>(ptr); ptr += 8;
+ ptr += 8; // skip flags, unused
+#ifdef ZT_TRACE
+ std::string addrs;
+#endif
+ unsigned int physicalAddressCount = dmsg[ptr++];
+ m.zeroTierPhysicalEndpoints.clear();
+ for(unsigned int i=0;i<physicalAddressCount;++i) {
+ m.zeroTierPhysicalEndpoints.push_back(InetAddress());
+ ptr += m.zeroTierPhysicalEndpoints.back().deserialize(dmsg,ptr);
+ if (!(m.zeroTierPhysicalEndpoints.back())) {
+ m.zeroTierPhysicalEndpoints.pop_back();
+ }
+#ifdef ZT_TRACE
+ else {
+ if (addrs.length() > 0)
+ addrs.push_back(',');
+ addrs.append(m.zeroTierPhysicalEndpoints.back().toString());
+ }
+#endif
+ }
+#ifdef ZT_TRACE
+ if ((RR->node->now() - m.lastReceivedAliveAnnouncement) >= ZT_CLUSTER_TIMEOUT) {
+ TRACE("[%u] I'm alive! peers close to %d,%d,%d can be redirected to: %s",(unsigned int)fromMemberId,m.x,m.y,m.z,addrs.c_str());
+ }
+#endif
+ m.lastReceivedAliveAnnouncement = RR->node->now();
+ } break;
+
+ case CLUSTER_MESSAGE_HAVE_PEER: {
+ Identity id;
+ ptr += id.deserialize(dmsg,ptr);
+ if (id) {
+ RR->topology->saveIdentity(id);
+
+ {
+ Mutex::Lock _l(_remotePeers_m);
+ _remotePeers[std::pair<Address,unsigned int>(id.address(),(unsigned int)fromMemberId)] = RR->node->now();
+ }
+
+ _ClusterSendQueueEntry *q[16384]; // 16384 is "tons"
+ unsigned int qc = _sendQueue->getByDest(id.address(),q,16384);
+ for(unsigned int i=0;i<qc;++i)
+ this->sendViaCluster(q[i]->fromPeerAddress,q[i]->toPeerAddress,q[i]->data,q[i]->len,q[i]->unite);
+ _sendQueue->returnToPool(q,qc);
+
+ TRACE("[%u] has %s (retried %u queued sends)",(unsigned int)fromMemberId,id.address().toString().c_str(),qc);
+ }
+ } break;
+
+ case CLUSTER_MESSAGE_WANT_PEER: {
+ const Address zeroTierAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH;
+ SharedPtr<Peer> peer(RR->topology->getPeerNoCache(zeroTierAddress));
+ if ( (peer) && (peer->hasClusterOptimalPath(RR->node->now())) ) {
+ Buffer<1024> buf;
+ peer->identity().serialize(buf);
+ Mutex::Lock _l2(_members[fromMemberId].lock);
+ _send(fromMemberId,CLUSTER_MESSAGE_HAVE_PEER,buf.data(),buf.size());
+ }
+ } break;
+
+ case CLUSTER_MESSAGE_REMOTE_PACKET: {
+ const unsigned int plen = dmsg.at<uint16_t>(ptr); ptr += 2;
+ if (plen) {
+ Packet remotep(dmsg.field(ptr,plen),plen); ptr += plen;
+ //TRACE("remote %s from %s via %u (%u bytes)",Packet::verbString(remotep.verb()),remotep.source().toString().c_str(),fromMemberId,plen);
+ switch(remotep.verb()) {
+ case Packet::VERB_WHOIS: _doREMOTE_WHOIS(fromMemberId,remotep); break;
+ case Packet::VERB_MULTICAST_GATHER: _doREMOTE_MULTICAST_GATHER(fromMemberId,remotep); break;
+ default: break; // ignore things we don't care about across cluster
+ }
+ }
+ } break;
+
+ case CLUSTER_MESSAGE_PROXY_UNITE: {
+ const Address localPeerAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH;
+ const Address remotePeerAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH;
+ const unsigned int numRemotePeerPaths = dmsg[ptr++];
+ InetAddress remotePeerPaths[256]; // size is 8-bit, so 256 is max
+ for(unsigned int i=0;i<numRemotePeerPaths;++i)
+ ptr += remotePeerPaths[i].deserialize(dmsg,ptr);
+
+ TRACE("[%u] requested that we unite local %s with remote %s",(unsigned int)fromMemberId,localPeerAddress.toString().c_str(),remotePeerAddress.toString().c_str());
+
+ const uint64_t now = RR->node->now();
+ SharedPtr<Peer> localPeer(RR->topology->getPeerNoCache(localPeerAddress));
+ if ((localPeer)&&(numRemotePeerPaths > 0)) {
+ InetAddress bestLocalV4,bestLocalV6;
+ localPeer->getBestActiveAddresses(now,bestLocalV4,bestLocalV6);
+
+ InetAddress bestRemoteV4,bestRemoteV6;
+ for(unsigned int i=0;i<numRemotePeerPaths;++i) {
+ if ((bestRemoteV4)&&(bestRemoteV6))
+ break;
+ switch(remotePeerPaths[i].ss_family) {
+ case AF_INET:
+ if (!bestRemoteV4)
+ bestRemoteV4 = remotePeerPaths[i];
+ break;
+ case AF_INET6:
+ if (!bestRemoteV6)
+ bestRemoteV6 = remotePeerPaths[i];
+ break;
+ }
+ }
+
+ Packet rendezvousForLocal(localPeerAddress,RR->identity.address(),Packet::VERB_RENDEZVOUS);
+ rendezvousForLocal.append((uint8_t)0);
+ remotePeerAddress.appendTo(rendezvousForLocal);
+
+ Buffer<2048> rendezvousForRemote;
+ remotePeerAddress.appendTo(rendezvousForRemote);
+ rendezvousForRemote.append((uint8_t)Packet::VERB_RENDEZVOUS);
+ rendezvousForRemote.addSize(2); // space for actual packet payload length
+ rendezvousForRemote.append((uint8_t)0); // flags == 0
+ localPeerAddress.appendTo(rendezvousForRemote);
+
+ bool haveMatch = false;
+ if ((bestLocalV6)&&(bestRemoteV6)) {
+ haveMatch = true;
+
+ rendezvousForLocal.append((uint16_t)bestRemoteV6.port());
+ rendezvousForLocal.append((uint8_t)16);
+ rendezvousForLocal.append(bestRemoteV6.rawIpData(),16);
+
+ rendezvousForRemote.append((uint16_t)bestLocalV6.port());
+ rendezvousForRemote.append((uint8_t)16);
+ rendezvousForRemote.append(bestLocalV6.rawIpData(),16);
+ rendezvousForRemote.setAt<uint16_t>(ZT_ADDRESS_LENGTH + 1,(uint16_t)(9 + 16));
+ } else if ((bestLocalV4)&&(bestRemoteV4)) {
+ haveMatch = true;
+
+ rendezvousForLocal.append((uint16_t)bestRemoteV4.port());
+ rendezvousForLocal.append((uint8_t)4);
+ rendezvousForLocal.append(bestRemoteV4.rawIpData(),4);
+
+ rendezvousForRemote.append((uint16_t)bestLocalV4.port());
+ rendezvousForRemote.append((uint8_t)4);
+ rendezvousForRemote.append(bestLocalV4.rawIpData(),4);
+ rendezvousForRemote.setAt<uint16_t>(ZT_ADDRESS_LENGTH + 1,(uint16_t)(9 + 4));
+ }
+
+ if (haveMatch) {
+ {
+ Mutex::Lock _l2(_members[fromMemberId].lock);
+ _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,rendezvousForRemote.data(),rendezvousForRemote.size());
+ }
+ RR->sw->send(rendezvousForLocal,true,0);
+ }
+ }
+ } break;
+
+ case CLUSTER_MESSAGE_PROXY_SEND: {
+ const Address rcpt(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH;
+ const Packet::Verb verb = (Packet::Verb)dmsg[ptr++];
+ const unsigned int len = dmsg.at<uint16_t>(ptr); ptr += 2;
+ Packet outp(rcpt,RR->identity.address(),verb);
+ outp.append(dmsg.field(ptr,len),len); ptr += len;
+ RR->sw->send(outp,true,0);
+ //TRACE("[%u] proxy send %s to %s length %u",(unsigned int)fromMemberId,Packet::verbString(verb),rcpt.toString().c_str(),len);
+ } break;
+ }
+ } catch ( ... ) {
+ TRACE("invalid message of size %u type %d (inner decode), discarding",mlen,mtype);
+ // drop invalids
+ }
+
+ ptr = nextPtr;
+ }
+ } catch ( ... ) {
+ TRACE("invalid message (outer loop), discarding");
+ // drop invalids
+ }
+}
+
+void Cluster::broadcastHavePeer(const Identity &id)
+{
+ Buffer<1024> buf;
+ id.serialize(buf);
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ Mutex::Lock _l2(_members[*mid].lock);
+ _send(*mid,CLUSTER_MESSAGE_HAVE_PEER,buf.data(),buf.size());
+ }
+}
+
+void Cluster::sendViaCluster(const Address &fromPeerAddress,const Address &toPeerAddress,const void *data,unsigned int len,bool unite)
+{
+ if (len > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check
+ return;
+
+ const uint64_t now = RR->node->now();
+
+ uint64_t mostRecentTs = 0;
+ unsigned int mostRecentMemberId = 0xffffffff;
+ {
+ Mutex::Lock _l2(_remotePeers_m);
+ std::map< std::pair<Address,unsigned int>,uint64_t >::const_iterator rpe(_remotePeers.lower_bound(std::pair<Address,unsigned int>(toPeerAddress,0)));
+ for(;;) {
+ if ((rpe == _remotePeers.end())||(rpe->first.first != toPeerAddress))
+ break;
+ else if (rpe->second > mostRecentTs) {
+ mostRecentTs = rpe->second;
+ mostRecentMemberId = rpe->first.second;
+ }
+ ++rpe;
+ }
+ }
+
+ const uint64_t age = now - mostRecentTs;
+ if (age >= (ZT_PEER_ACTIVITY_TIMEOUT / 3)) {
+ const bool enqueueAndWait = ((age >= ZT_PEER_ACTIVITY_TIMEOUT)||(mostRecentMemberId > 0xffff));
+
+ // Poll everyone with WANT_PEER if the age of our most recent entry is
+ // approaching expiration (or has expired, or does not exist).
+ char tmp[ZT_ADDRESS_LENGTH];
+ toPeerAddress.copyTo(tmp,ZT_ADDRESS_LENGTH);
+ {
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ Mutex::Lock _l2(_members[*mid].lock);
+ _send(*mid,CLUSTER_MESSAGE_WANT_PEER,tmp,ZT_ADDRESS_LENGTH);
+ }
+ }
+
+ // If there isn't a good place to send via, then enqueue this for retrying
+ // later and return after having broadcasted a WANT_PEER.
+ if (enqueueAndWait) {
+ TRACE("sendViaCluster %s -> %s enqueueing to wait for HAVE_PEER",fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str());
+ _sendQueue->enqueue(now,fromPeerAddress,toPeerAddress,data,len,unite);
+ return;
+ }
+ }
+
+ Buffer<1024> buf;
+ if (unite) {
+ InetAddress v4,v6;
+ if (fromPeerAddress) {
+ SharedPtr<Peer> fromPeer(RR->topology->getPeerNoCache(fromPeerAddress));
+ if (fromPeer)
+ fromPeer->getBestActiveAddresses(now,v4,v6);
+ }
+ uint8_t addrCount = 0;
+ if (v4)
+ ++addrCount;
+ if (v6)
+ ++addrCount;
+ if (addrCount) {
+ toPeerAddress.appendTo(buf);
+ fromPeerAddress.appendTo(buf);
+ buf.append(addrCount);
+ if (v4)
+ v4.serialize(buf);
+ if (v6)
+ v6.serialize(buf);
+ }
+ }
+
+ {
+ Mutex::Lock _l2(_members[mostRecentMemberId].lock);
+ if (buf.size() > 0)
+ _send(mostRecentMemberId,CLUSTER_MESSAGE_PROXY_UNITE,buf.data(),buf.size());
+ if (_members[mostRecentMemberId].zeroTierPhysicalEndpoints.size() > 0) {
+ TRACE("sendViaCluster relaying %u bytes from %s to %s by way of %u",len,fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str(),(unsigned int)mostRecentMemberId);
+ RR->node->putPacket(InetAddress(),_members[mostRecentMemberId].zeroTierPhysicalEndpoints.front(),data,len);
+ }
+ }
+}
+
+void Cluster::sendDistributedQuery(const Packet &pkt)
+{
+ Buffer<4096> buf;
+ buf.append((uint16_t)pkt.size());
+ buf.append(pkt.data(),pkt.size());
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ Mutex::Lock _l2(_members[*mid].lock);
+ _send(*mid,CLUSTER_MESSAGE_REMOTE_PACKET,buf.data(),buf.size());
+ }
+}
+
+void Cluster::doPeriodicTasks()
+{
+ const uint64_t now = RR->node->now();
+
+ if ((now - _lastFlushed) >= ZT_CLUSTER_FLUSH_PERIOD) {
+ _lastFlushed = now;
+
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ Mutex::Lock _l2(_members[*mid].lock);
+
+ if ((now - _members[*mid].lastAnnouncedAliveTo) >= ((ZT_CLUSTER_TIMEOUT / 2) - 1000)) {
+ _members[*mid].lastAnnouncedAliveTo = now;
+
+ Buffer<2048> alive;
+ alive.append((uint16_t)ZEROTIER_ONE_VERSION_MAJOR);
+ alive.append((uint16_t)ZEROTIER_ONE_VERSION_MINOR);
+ alive.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
+ alive.append((uint8_t)ZT_PROTO_VERSION);
+ if (_addressToLocationFunction) {
+ alive.append((int32_t)_x);
+ alive.append((int32_t)_y);
+ alive.append((int32_t)_z);
+ } else {
+ alive.append((int32_t)0);
+ alive.append((int32_t)0);
+ alive.append((int32_t)0);
+ }
+ alive.append((uint64_t)now);
+ alive.append((uint64_t)0); // TODO: compute and send load average
+ alive.append((uint64_t)RR->topology->countActive(now));
+ alive.append((uint64_t)0); // unused/reserved flags
+ alive.append((uint8_t)_zeroTierPhysicalEndpoints.size());
+ for(std::vector<InetAddress>::const_iterator pe(_zeroTierPhysicalEndpoints.begin());pe!=_zeroTierPhysicalEndpoints.end();++pe)
+ pe->serialize(alive);
+ _send(*mid,CLUSTER_MESSAGE_ALIVE,alive.data(),alive.size());
+ }
+
+ _flush(*mid);
+ }
+ }
+
+ if ((now - _lastCleanedRemotePeers) >= (ZT_PEER_ACTIVITY_TIMEOUT * 2)) {
+ _lastCleanedRemotePeers = now;
+
+ Mutex::Lock _l(_remotePeers_m);
+ for(std::map< std::pair<Address,unsigned int>,uint64_t >::iterator rp(_remotePeers.begin());rp!=_remotePeers.end();) {
+ if ((now - rp->second) >= ZT_PEER_ACTIVITY_TIMEOUT)
+ _remotePeers.erase(rp++);
+ else ++rp;
+ }
+ }
+
+ if ((now - _lastCleanedQueue) >= ZT_CLUSTER_QUEUE_EXPIRATION) {
+ _lastCleanedQueue = now;
+ _sendQueue->expire(now);
+ }
+}
+
+void Cluster::addMember(uint16_t memberId)
+{
+ if ((memberId >= ZT_CLUSTER_MAX_MEMBERS)||(memberId == _id))
+ return;
+
+ Mutex::Lock _l2(_members[memberId].lock);
+
+ {
+ Mutex::Lock _l(_memberIds_m);
+ if (std::find(_memberIds.begin(),_memberIds.end(),memberId) != _memberIds.end())
+ return;
+ _memberIds.push_back(memberId);
+ std::sort(_memberIds.begin(),_memberIds.end());
+ }
+
+ _members[memberId].clear();
+
+ // Generate this member's message key from the master and its ID
+ uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)];
+ memcpy(stmp,_masterSecret,sizeof(stmp));
+ stmp[0] ^= Utils::hton(memberId);
+ SHA512::hash(stmp,stmp,sizeof(stmp));
+ SHA512::hash(stmp,stmp,sizeof(stmp));
+ memcpy(_members[memberId].key,stmp,sizeof(_members[memberId].key));
+ Utils::burn(stmp,sizeof(stmp));
+
+ // Prepare q
+ _members[memberId].q.clear();
+ char iv[16];
+ Utils::getSecureRandom(iv,16);
+ _members[memberId].q.append(iv,16);
+ _members[memberId].q.addSize(8); // room for MAC
+ _members[memberId].q.append((uint16_t)_id);
+ _members[memberId].q.append((uint16_t)memberId);
+}
+
+void Cluster::removeMember(uint16_t memberId)
+{
+ Mutex::Lock _l(_memberIds_m);
+ std::vector<uint16_t> newMemberIds;
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ if (*mid != memberId)
+ newMemberIds.push_back(*mid);
+ }
+ _memberIds = newMemberIds;
+}
+
+bool Cluster::findBetterEndpoint(InetAddress &redirectTo,const Address &peerAddress,const InetAddress &peerPhysicalAddress,bool offload)
+{
+ if (_addressToLocationFunction) {
+ // Pick based on location if it can be determined
+ int px = 0,py = 0,pz = 0;
+ if (_addressToLocationFunction(_addressToLocationFunctionArg,reinterpret_cast<const struct sockaddr_storage *>(&peerPhysicalAddress),&px,&py,&pz) == 0) {
+ TRACE("no geolocation data for %s (geo-lookup is lazy/async so it may work next time)",peerPhysicalAddress.toIpString().c_str());
+ return false;
+ }
+
+ // Find member closest to this peer
+ const uint64_t now = RR->node->now();
+ std::vector<InetAddress> best;
+ const double currentDistance = _dist3d(_x,_y,_z,px,py,pz);
+ double bestDistance = (offload ? 2147483648.0 : currentDistance);
+ unsigned int bestMember = _id;
+ {
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ _Member &m = _members[*mid];
+ Mutex::Lock _ml(m.lock);
+
+ // Consider member if it's alive and has sent us a location and one or more physical endpoints to send peers to
+ if ( ((now - m.lastReceivedAliveAnnouncement) < ZT_CLUSTER_TIMEOUT) && ((m.x != 0)||(m.y != 0)||(m.z != 0)) && (m.zeroTierPhysicalEndpoints.size() > 0) ) {
+ const double mdist = _dist3d(m.x,m.y,m.z,px,py,pz);
+ if (mdist < bestDistance) {
+ bestDistance = mdist;
+ bestMember = *mid;
+ best = m.zeroTierPhysicalEndpoints;
+ }
+ }
+ }
+ }
+
+ // Redirect to a closer member if it has a ZeroTier endpoint address in the same ss_family
+ for(std::vector<InetAddress>::const_iterator a(best.begin());a!=best.end();++a) {
+ if (a->ss_family == peerPhysicalAddress.ss_family) {
+ TRACE("%s at [%d,%d,%d] is %f from us but %f from %u, can redirect to %s",peerAddress.toString().c_str(),px,py,pz,currentDistance,bestDistance,bestMember,a->toString().c_str());
+ redirectTo = *a;
+ return true;
+ }
+ }
+ TRACE("%s at [%d,%d,%d] is %f from us, no better endpoints found",peerAddress.toString().c_str(),px,py,pz,currentDistance);
+ return false;
+ } else {
+ // TODO: pick based on load if no location info?
+ return false;
+ }
+}
+
+void Cluster::status(ZT_ClusterStatus &status) const
+{
+ const uint64_t now = RR->node->now();
+ memset(&status,0,sizeof(ZT_ClusterStatus));
+
+ status.myId = _id;
+
+ {
+ ZT_ClusterMemberStatus *const s = &(status.members[status.clusterSize++]);
+ s->id = _id;
+ s->alive = 1;
+ s->x = _x;
+ s->y = _y;
+ s->z = _z;
+ s->load = 0; // TODO
+ s->peers = RR->topology->countActive(now);
+ for(std::vector<InetAddress>::const_iterator ep(_zeroTierPhysicalEndpoints.begin());ep!=_zeroTierPhysicalEndpoints.end();++ep) {
+ if (s->numZeroTierPhysicalEndpoints >= ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES) // sanity check
+ break;
+ memcpy(&(s->zeroTierPhysicalEndpoints[s->numZeroTierPhysicalEndpoints++]),&(*ep),sizeof(struct sockaddr_storage));
+ }
+ }
+
+ {
+ Mutex::Lock _l1(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ if (status.clusterSize >= ZT_CLUSTER_MAX_MEMBERS) // sanity check
+ break;
+
+ _Member &m = _members[*mid];
+ Mutex::Lock ml(m.lock);
+
+ ZT_ClusterMemberStatus *const s = &(status.members[status.clusterSize++]);
+ s->id = *mid;
+ s->msSinceLastHeartbeat = (unsigned int)std::min((uint64_t)(~((unsigned int)0)),(now - m.lastReceivedAliveAnnouncement));
+ s->alive = (s->msSinceLastHeartbeat < ZT_CLUSTER_TIMEOUT) ? 1 : 0;
+ s->x = m.x;
+ s->y = m.y;
+ s->z = m.z;
+ s->load = m.load;
+ s->peers = m.peers;
+ for(std::vector<InetAddress>::const_iterator ep(m.zeroTierPhysicalEndpoints.begin());ep!=m.zeroTierPhysicalEndpoints.end();++ep) {
+ if (s->numZeroTierPhysicalEndpoints >= ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES) // sanity check
+ break;
+ memcpy(&(s->zeroTierPhysicalEndpoints[s->numZeroTierPhysicalEndpoints++]),&(*ep),sizeof(struct sockaddr_storage));
+ }
+ }
+ }
+}
+
+void Cluster::_send(uint16_t memberId,StateMessageType type,const void *msg,unsigned int len)
+{
+ if ((len + 3) > (ZT_CLUSTER_MAX_MESSAGE_LENGTH - (24 + 2 + 2))) // sanity check
+ return;
+ _Member &m = _members[memberId];
+ // assumes m.lock is locked!
+ if ((m.q.size() + len + 3) > ZT_CLUSTER_MAX_MESSAGE_LENGTH)
+ _flush(memberId);
+ m.q.append((uint16_t)(len + 1));
+ m.q.append((uint8_t)type);
+ m.q.append(msg,len);
+}
+
+void Cluster::_flush(uint16_t memberId)
+{
+ _Member &m = _members[memberId];
+ // assumes m.lock is locked!
+ if (m.q.size() > (24 + 2 + 2)) { // 16-byte IV + 8-byte MAC + 2 byte from-member-ID + 2 byte to-member-ID
+ // Create key from member's key and IV
+ char keytmp[32];
+ memcpy(keytmp,m.key,32);
+ for(int i=0;i<8;++i)
+ keytmp[i] ^= m.q[i];
+ Salsa20 s20(keytmp,256,m.q.field(8,8));
+ Utils::burn(keytmp,sizeof(keytmp));
+
+ // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
+ char polykey[ZT_POLY1305_KEY_LEN];
+ memset(polykey,0,sizeof(polykey));
+ s20.encrypt12(polykey,polykey,sizeof(polykey));
+
+ // Encrypt m.q in place
+ s20.encrypt12(reinterpret_cast<const char *>(m.q.data()) + 24,const_cast<char *>(reinterpret_cast<const char *>(m.q.data())) + 24,m.q.size() - 24);
+
+ // Add MAC for authentication (encrypt-then-MAC)
+ char mac[ZT_POLY1305_MAC_LEN];
+ Poly1305::compute(mac,reinterpret_cast<const char *>(m.q.data()) + 24,m.q.size() - 24,polykey);
+ memcpy(m.q.field(16,8),mac,8);
+
+ // Send!
+ _sendFunction(_sendFunctionArg,memberId,m.q.data(),m.q.size());
+
+ // Prepare for more
+ m.q.clear();
+ char iv[16];
+ Utils::getSecureRandom(iv,16);
+ m.q.append(iv,16);
+ m.q.addSize(8); // room for MAC
+ m.q.append((uint16_t)_id); // from member ID
+ m.q.append((uint16_t)memberId); // to member ID
+ }
+}
+
+void Cluster::_doREMOTE_WHOIS(uint64_t fromMemberId,const Packet &remotep)
+{
+ if (remotep.payloadLength() >= ZT_ADDRESS_LENGTH) {
+ Identity queried(RR->topology->getIdentity(Address(remotep.payload(),ZT_ADDRESS_LENGTH)));
+ if (queried) {
+ Buffer<1024> routp;
+ remotep.source().appendTo(routp);
+ routp.append((uint8_t)Packet::VERB_OK);
+ routp.addSize(2); // space for length
+ routp.append((uint8_t)Packet::VERB_WHOIS);
+ routp.append(remotep.packetId());
+ queried.serialize(routp);
+ routp.setAt<uint16_t>(ZT_ADDRESS_LENGTH + 1,(uint16_t)(routp.size() - ZT_ADDRESS_LENGTH - 3));
+
+ TRACE("responding to remote WHOIS from %s @ %u with identity of %s",remotep.source().toString().c_str(),(unsigned int)fromMemberId,queried.address().toString().c_str());
+ Mutex::Lock _l2(_members[fromMemberId].lock);
+ _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,routp.data(),routp.size());
+ }
+ }
+}
+
+void Cluster::_doREMOTE_MULTICAST_GATHER(uint64_t fromMemberId,const Packet &remotep)
+{
+ const uint64_t nwid = remotep.at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID);
+ const MulticastGroup mg(MAC(remotep.field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),remotep.at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI));
+ unsigned int gatherLimit = remotep.at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT);
+ const Address remotePeerAddress(remotep.source());
+
+ if (gatherLimit) {
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH> routp;
+ remotePeerAddress.appendTo(routp);
+ routp.append((uint8_t)Packet::VERB_OK);
+ routp.addSize(2); // space for length
+ routp.append((uint8_t)Packet::VERB_MULTICAST_GATHER);
+ routp.append(remotep.packetId());
+ routp.append(nwid);
+ mg.mac().appendTo(routp);
+ routp.append((uint32_t)mg.adi());
+
+ if (gatherLimit > ((ZT_CLUSTER_MAX_MESSAGE_LENGTH - 80) / 5))
+ gatherLimit = ((ZT_CLUSTER_MAX_MESSAGE_LENGTH - 80) / 5);
+ if (RR->mc->gather(remotePeerAddress,nwid,mg,routp,gatherLimit)) {
+ routp.setAt<uint16_t>(ZT_ADDRESS_LENGTH + 1,(uint16_t)(routp.size() - ZT_ADDRESS_LENGTH - 3));
+
+ TRACE("responding to remote MULTICAST_GATHER from %s @ %u with %u bytes",remotePeerAddress.toString().c_str(),(unsigned int)fromMemberId,routp.size());
+ Mutex::Lock _l2(_members[fromMemberId].lock);
+ _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,routp.data(),routp.size());
+ }
+ }
+}
+
+} // namespace ZeroTier
+
+#endif // ZT_ENABLE_CLUSTER
diff --git a/node/Cluster.hpp b/node/Cluster.hpp
new file mode 100644
index 00000000..ccf0c12a
--- /dev/null
+++ b/node/Cluster.hpp
@@ -0,0 +1,418 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_CLUSTER_HPP
+#define ZT_CLUSTER_HPP
+
+#ifdef ZT_ENABLE_CLUSTER
+
+#include <map>
+
+#include "Constants.hpp"
+#include "../include/ZeroTierOne.h"
+#include "Address.hpp"
+#include "InetAddress.hpp"
+#include "SHA512.hpp"
+#include "Utils.hpp"
+#include "Buffer.hpp"
+#include "Mutex.hpp"
+#include "SharedPtr.hpp"
+#include "Hashtable.hpp"
+#include "Packet.hpp"
+#include "SharedPtr.hpp"
+
+/**
+ * Timeout for cluster members being considered "alive"
+ *
+ * A cluster member is considered dead and will no longer have peers
+ * redirected to it if we have not heard a heartbeat in this long.
+ */
+#define ZT_CLUSTER_TIMEOUT 5000
+
+/**
+ * Desired period between doPeriodicTasks() in milliseconds
+ */
+#define ZT_CLUSTER_PERIODIC_TASK_PERIOD 50
+
+/**
+ * How often to flush outgoing message queues (maximum interval)
+ */
+#define ZT_CLUSTER_FLUSH_PERIOD 100
+
+/**
+ * Maximum number of queued outgoing packets per sender address
+ */
+#define ZT_CLUSTER_MAX_QUEUE_PER_SENDER 8
+
+/**
+ * Expiration time for send queue entries
+ */
+#define ZT_CLUSTER_QUEUE_EXPIRATION 5000
+
+/**
+ * Chunk size for allocating queue entries
+ *
+ * Queue entries are allocated in chunks of this many and are added to a pool.
+ * ZT_CLUSTER_MAX_QUEUE_GLOBAL must be evenly divisible by this.
+ */
+#define ZT_CLUSTER_QUEUE_CHUNK_SIZE 32
+
+/**
+ * Maximum number of chunks to ever allocate
+ *
+ * This is a global sanity limit to prevent resource exhaustion attacks. It
+ * works out to about 600mb of RAM. You'll never see this on a normal edge
+ * node. We're unlikely to see this on a root server unless someone is DOSing
+ * us. In that case cluster relaying will be affected but other functions
+ * should continue to operate normally.
+ */
+#define ZT_CLUSTER_MAX_QUEUE_CHUNKS 8194
+
+/**
+ * Max data per queue entry
+ *
+ * If we ever support larger transport MTUs this must be increased. The plus
+ * 16 is just a small margin and has no special meaning.
+ */
+#define ZT_CLUSTER_SEND_QUEUE_DATA_MAX (ZT_UDP_DEFAULT_PAYLOAD_MTU + 16)
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+class MulticastGroup;
+class Peer;
+class Identity;
+
+// Internal class implemented inside Cluster.cpp
+class _ClusterSendQueue;
+
+/**
+ * Multi-homing cluster state replication and packet relaying
+ *
+ * Multi-homing means more than one node sharing the same ZeroTier identity.
+ * There is nothing in the protocol to prevent this, but to make it work well
+ * requires the devices sharing an identity to cooperate and share some
+ * information.
+ *
+ * There are three use cases we want to fulfill:
+ *
+ * (1) Multi-homing of root servers with handoff for efficient routing,
+ * HA, and load balancing across many commodity nodes.
+ * (2) Multi-homing of network controllers for the same reason.
+ * (3) Multi-homing of nodes on virtual networks, such as domain servers
+ * and other important endpoints.
+ *
+ * These use cases are in order of escalating difficulty. The initial
+ * version of Cluster is aimed at satisfying the first, though you are
+ * free to try #2 and #3.
+ */
+class Cluster
+{
+public:
+ /**
+ * State message types
+ */
+ enum StateMessageType
+ {
+ CLUSTER_MESSAGE_NOP = 0,
+
+ /**
+ * This cluster member is alive:
+ * <[2] version minor>
+ * <[2] version major>
+ * <[2] version revision>
+ * <[1] protocol version>
+ * <[4] X location (signed 32-bit)>
+ * <[4] Y location (signed 32-bit)>
+ * <[4] Z location (signed 32-bit)>
+ * <[8] local clock at this member>
+ * <[8] load average>
+ * <[8] number of peers>
+ * <[8] flags (currently unused, must be zero)>
+ * <[1] number of preferred ZeroTier endpoints>
+ * <[...] InetAddress(es) of preferred ZeroTier endpoint(s)>
+ *
+ * Cluster members constantly broadcast an alive heartbeat and will only
+ * receive peer redirects if they've done so within the timeout.
+ */
+ CLUSTER_MESSAGE_ALIVE = 1,
+
+ /**
+ * Cluster member has this peer:
+ * <[...] serialized identity of peer>
+ *
+ * This is typically sent in response to WANT_PEER but can also be pushed
+ * to prepopulate if this makes sense.
+ */
+ CLUSTER_MESSAGE_HAVE_PEER = 2,
+
+ /**
+ * Cluster member wants this peer:
+ * <[5] ZeroTier address of peer>
+ *
+ * Members that have a direct link to this peer will respond with
+ * HAVE_PEER.
+ */
+ CLUSTER_MESSAGE_WANT_PEER = 3,
+
+ /**
+ * A remote packet that we should also possibly respond to:
+ * <[2] 16-bit length of remote packet>
+ * <[...] remote packet payload>
+ *
+ * Cluster members may relay requests by relaying the request packet.
+ * These may include requests such as WHOIS and MULTICAST_GATHER. The
+ * packet must be already decrypted, decompressed, and authenticated.
+ *
+ * This can only be used for small request packets as per the cluster
+ * message size limit, but since these are the only ones in question
+ * this is fine.
+ *
+ * If a response is generated it is sent via PROXY_SEND.
+ */
+ CLUSTER_MESSAGE_REMOTE_PACKET = 4,
+
+ /**
+ * Request that VERB_RENDEZVOUS be sent to a peer that we have:
+ * <[5] ZeroTier address of peer on recipient's side>
+ * <[5] ZeroTier address of peer on sender's side>
+ * <[1] 8-bit number of sender's peer's active path addresses>
+ * <[...] series of serialized InetAddresses of sender's peer's paths>
+ *
+ * This requests that we perform NAT-t introduction between a peer that
+ * we have and one on the sender's side. The sender furnishes contact
+ * info for its peer, and we send VERB_RENDEZVOUS to both sides: to ours
+ * directly and with PROXY_SEND to theirs.
+ */
+ CLUSTER_MESSAGE_PROXY_UNITE = 5,
+
+ /**
+ * Request that a cluster member send a packet to a locally-known peer:
+ * <[5] ZeroTier address of recipient>
+ * <[1] packet verb>
+ * <[2] length of packet payload>
+ * <[...] packet payload>
+ *
+ * This differs from RELAY in that it requests the receiving cluster
+ * member to actually compose a ZeroTier Packet from itself to the
+ * provided recipient. RELAY simply says "please forward this blob."
+ * RELAY is used to implement peer-to-peer relaying with RENDEZVOUS,
+ * while PROXY_SEND is used to implement proxy sending (which right
+ * now is only used to send RENDEZVOUS).
+ */
+ CLUSTER_MESSAGE_PROXY_SEND = 6,
+
+ /**
+ * Replicate a network config for a network we belong to:
+ * <[8] 64-bit network ID>
+ * <[2] 16-bit length of network config>
+ * <[...] serialized network config>
+ *
+ * This is used by clusters to avoid every member having to query
+ * for the same netconf for networks all members belong to.
+ *
+ * TODO: not implemented yet!
+ */
+ CLUSTER_MESSAGE_NETWORK_CONFIG = 7
+ };
+
+ /**
+ * Construct a new cluster
+ */
+ Cluster(
+ const RuntimeEnvironment *renv,
+ uint16_t id,
+ const std::vector<InetAddress> &zeroTierPhysicalEndpoints,
+ int32_t x,
+ int32_t y,
+ int32_t z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg);
+
+ ~Cluster();
+
+ /**
+ * @return This cluster member's ID
+ */
+ inline uint16_t id() const throw() { return _id; }
+
+ /**
+ * Handle an incoming intra-cluster message
+ *
+ * @param data Message data
+ * @param len Message length (max: ZT_CLUSTER_MAX_MESSAGE_LENGTH)
+ */
+ void handleIncomingStateMessage(const void *msg,unsigned int len);
+
+ /**
+ * Broadcast that we have a given peer
+ *
+ * This should be done when new peers are first contacted.
+ *
+ * @param id Identity of peer
+ */
+ void broadcastHavePeer(const Identity &id);
+
+ /**
+ * Send this packet via another node in this cluster if another node has this peer
+ *
+ * This is used in the outgoing packet and relaying logic in Switch to
+ * relay packets to other cluster members. It isn't PROXY_SEND-- that is
+ * used internally in Cluster to send responses to peer queries.
+ *
+ * @param fromPeerAddress Source peer address (if known, should be NULL for fragments)
+ * @param toPeerAddress Destination peer address
+ * @param data Packet or packet fragment data
+ * @param len Length of packet or fragment
+ * @param unite If true, also request proxy unite across cluster
+ */
+ void sendViaCluster(const Address &fromPeerAddress,const Address &toPeerAddress,const void *data,unsigned int len,bool unite);
+
+ /**
+ * Send a distributed query to other cluster members
+ *
+ * Some queries such as WHOIS or MULTICAST_GATHER need a response from other
+ * cluster members. Replies (if any) will be sent back to the peer via
+ * PROXY_SEND across the cluster.
+ *
+ * @param pkt Packet to distribute
+ */
+ void sendDistributedQuery(const Packet &pkt);
+
+ /**
+ * Call every ~ZT_CLUSTER_PERIODIC_TASK_PERIOD milliseconds.
+ */
+ void doPeriodicTasks();
+
+ /**
+ * Add a member ID to this cluster
+ *
+ * @param memberId Member ID
+ */
+ void addMember(uint16_t memberId);
+
+ /**
+ * Remove a member ID from this cluster
+ *
+ * @param memberId Member ID to remove
+ */
+ void removeMember(uint16_t memberId);
+
+ /**
+ * Find a better cluster endpoint for this peer (if any)
+ *
+ * @param redirectTo InetAddress to be set to a better endpoint (if there is one)
+ * @param peerAddress Address of peer to (possibly) redirect
+ * @param peerPhysicalAddress Physical address of peer's current best path (where packet was most recently received or getBestPath()->address())
+ * @param offload Always redirect if possible -- can be used to offload peers during shutdown
+ * @return True if redirectTo was set to a new address, false if redirectTo was not modified
+ */
+ bool findBetterEndpoint(InetAddress &redirectTo,const Address &peerAddress,const InetAddress &peerPhysicalAddress,bool offload);
+
+ /**
+ * Fill out ZT_ClusterStatus structure (from core API)
+ *
+ * @param status Reference to structure to hold result (anything there is replaced)
+ */
+ void status(ZT_ClusterStatus &status) const;
+
+private:
+ void _send(uint16_t memberId,StateMessageType type,const void *msg,unsigned int len);
+ void _flush(uint16_t memberId);
+
+ void _doREMOTE_WHOIS(uint64_t fromMemberId,const Packet &remotep);
+ void _doREMOTE_MULTICAST_GATHER(uint64_t fromMemberId,const Packet &remotep);
+
+ // These are initialized in the constructor and remain immutable ------------
+ uint16_t _masterSecret[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)];
+ unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH];
+ const RuntimeEnvironment *RR;
+ _ClusterSendQueue *const _sendQueue;
+ void (*_sendFunction)(void *,unsigned int,const void *,unsigned int);
+ void *_sendFunctionArg;
+ int (*_addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *);
+ void *_addressToLocationFunctionArg;
+ const int32_t _x;
+ const int32_t _y;
+ const int32_t _z;
+ const uint16_t _id;
+ const std::vector<InetAddress> _zeroTierPhysicalEndpoints;
+ // end immutable fields -----------------------------------------------------
+
+ struct _Member
+ {
+ unsigned char key[ZT_PEER_SECRET_KEY_LENGTH];
+
+ uint64_t lastReceivedAliveAnnouncement;
+ uint64_t lastAnnouncedAliveTo;
+
+ uint64_t load;
+ uint64_t peers;
+ int32_t x,y,z;
+
+ std::vector<InetAddress> zeroTierPhysicalEndpoints;
+
+ Buffer<ZT_CLUSTER_MAX_MESSAGE_LENGTH> q;
+
+ Mutex lock;
+
+ inline void clear()
+ {
+ lastReceivedAliveAnnouncement = 0;
+ lastAnnouncedAliveTo = 0;
+ load = 0;
+ peers = 0;
+ x = 0;
+ y = 0;
+ z = 0;
+ zeroTierPhysicalEndpoints.clear();
+ q.clear();
+ }
+
+ _Member() { this->clear(); }
+ ~_Member() { Utils::burn(key,sizeof(key)); }
+ };
+ _Member *const _members;
+
+ std::vector<uint16_t> _memberIds;
+ Mutex _memberIds_m;
+
+ std::map< std::pair<Address,unsigned int>,uint64_t > _remotePeers; // we need ordered behavior and lower_bound here
+ Mutex _remotePeers_m;
+
+ uint64_t _lastFlushed;
+ uint64_t _lastCleanedRemotePeers;
+ uint64_t _lastCleanedQueue;
+};
+
+} // namespace ZeroTier
+
+#endif // ZT_ENABLE_CLUSTER
+
+#endif
diff --git a/node/Constants.hpp b/node/Constants.hpp
index 6e9f5b15..220d78ed 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -173,16 +173,11 @@
/**
* Timeout for receipt of fragmented packets in ms
- *
- * Since there's no retransmits, this is just a really bad case scenario for
- * transit time. It's short enough that a DOS attack from exhausing buffers is
- * very unlikely, as the transfer rate would have to be fast enough to fill
- * system memory in this time.
*/
-#define ZT_FRAGMENTED_PACKET_RECEIVE_TIMEOUT 1000
+#define ZT_FRAGMENTED_PACKET_RECEIVE_TIMEOUT 500
/**
- * Length of secret key in bytes -- 256-bit for Salsa20
+ * Length of secret key in bytes -- 256-bit -- do not change
*/
#define ZT_PEER_SECRET_KEY_LENGTH 32
@@ -194,7 +189,7 @@
/**
* Overriding granularity for timer tasks to prevent CPU-intensive thrashing on every packet
*/
-#define ZT_CORE_TIMER_TASK_GRANULARITY 1000
+#define ZT_CORE_TIMER_TASK_GRANULARITY 500
/**
* How long to remember peer records in RAM if they haven't been used
@@ -204,7 +199,7 @@
/**
* Delay between WHOIS retries in ms
*/
-#define ZT_WHOIS_RETRY_DELAY 500
+#define ZT_WHOIS_RETRY_DELAY 1000
/**
* Maximum identity WHOIS retries (each attempt tries consulting a different peer)
@@ -264,33 +259,22 @@
* This is also how often pings will be retried to upstream peers (relays, roots)
* constantly until something is heard.
*/
-#define ZT_PING_CHECK_INVERVAL 6250
+#define ZT_PING_CHECK_INVERVAL 9500
/**
* Delay between ordinary case pings of direct links
*/
-#define ZT_PEER_DIRECT_PING_DELAY 120000
-
-/**
- * Delay between requests for updated network autoconf information
- */
-#define ZT_NETWORK_AUTOCONF_DELAY 60000
+#define ZT_PEER_DIRECT_PING_DELAY 60000
/**
* Timeout for overall peer activity (measured from last receive)
*/
-#define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_DIRECT_PING_DELAY + (ZT_PING_CHECK_INVERVAL * 3))
+#define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 4) + ZT_PING_CHECK_INVERVAL)
/**
- * Stop relaying via peers that have not responded to direct sends
- *
- * When we send something (including frames), we generally expect a response.
- * Switching relays if no response in a short period of time causes more
- * rapid failover if a root server goes down or becomes unreachable. In the
- * mistaken case, little harm is done as it'll pick the next-fastest
- * root server and will switch back eventually.
+ * Delay between requests for updated network autoconf information
*/
-#define ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD 10000
+#define ZT_NETWORK_AUTOCONF_DELAY 60000
/**
* Minimum interval between attempts by relays to unite peers
@@ -299,7 +283,7 @@
* a RENDEZVOUS message no more than this often. This instructs the peers
* to attempt NAT-t and gives each the other's corresponding IP:port pair.
*/
-#define ZT_MIN_UNITE_INTERVAL 60000
+#define ZT_MIN_UNITE_INTERVAL 30000
/**
* Delay between initial direct NAT-t packet and more aggressive techniques
@@ -310,19 +294,9 @@
#define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000
/**
- * Size of anti-recursion history (see AntiRecursion.hpp)
- */
-#define ZT_ANTIRECURSION_HISTORY_SIZE 16
-
-/**
* Minimum delay between attempts to confirm new paths to peers (to avoid HELLO flooding)
*/
-#define ZT_MIN_PATH_CONFIRMATION_INTERVAL 5000
-
-/**
- * Interval between direct path pushes in milliseconds
- */
-#define ZT_DIRECT_PATH_PUSH_INTERVAL 300000
+#define ZT_MIN_PATH_CONFIRMATION_INTERVAL 1000
/**
* How long (max) to remember network certificates of membership?
@@ -348,6 +322,30 @@
#define ZT_MAX_BRIDGE_SPAM 16
/**
+ * Interval between direct path pushes in milliseconds
+ */
+#define ZT_DIRECT_PATH_PUSH_INTERVAL 120000
+
+/**
+ * Time horizon for push direct paths cutoff
+ */
+#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000
+
+/**
+ * Maximum number of direct path pushes within cutoff time
+ *
+ * This limits response to PUSH_DIRECT_PATHS to CUTOFF_LIMIT responses
+ * per CUTOFF_TIME milliseconds per peer to prevent this from being
+ * useful for DOS amplification attacks.
+ */
+#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5
+
+/**
+ * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
+ */
+#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 1
+
+/**
* A test pseudo-network-ID that can be joined
*
* Joining this network ID will result in a network with no IP addressing
diff --git a/node/Defaults.cpp b/node/Defaults.cpp
deleted file mode 100644
index b311fb6a..00000000
--- a/node/Defaults.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "../include/ZeroTierOne.h"
-
-#include "Constants.hpp"
-#include "Defaults.hpp"
-#include "Utils.hpp"
-
-// bin2c'd signed default root topology dictionary
-#include "../root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c"
-
-#ifdef __WINDOWS__
-#include <WinSock2.h>
-#include <Windows.h>
-#include <ShlObj.h>
-#endif
-
-namespace ZeroTier {
-
-const Defaults ZT_DEFAULTS;
-
-static inline std::map< Address,Identity > _mkRootTopologyAuth()
-{
- std::map< Address,Identity > ua;
-
- { // 0001
- Identity id("77792b1c02:0:b5c361e8e9c2154e82c3e902fdfc337468b092a7c4d8dc685c37eb10ee4f3c17cc0bb1d024167e8cb0824d12263428373582da3d0a9a14b36e4546c317e811e6");
- ua[id.address()] = id;
- }
- { // 0002
- Identity id("86921e6de1:0:9ba04f9f12ed54ef567f548cb69d31e404537d7b0ee000c63f3d7c8d490a1a47a5a5b2af0cbe12d23f9194270593f298d936d7c872612ea509ef1c67ce2c7fc1");
- ua[id.address()] = id;
- }
- { // 0003
- Identity id("90302b7025:0:358154a57af1b7afa07d0d91b69b92eaad2f11ade7f02343861f0c1b757d15626e8cb7f08fc52993d2202a39cbf5128c5647ee8c63d27d92db5a1d0fbe1eba19");
- ua[id.address()] = id;
- }
- { // 0004
- Identity id("e5174078ee:0:c3f90daa834a74ee47105f5726ae2e29fc8ae0e939c9326788b52b16d847354de8de3b13a81896bbb509b91e1da21763073a30bbfb2b8e994550798d30a2d709");
- ua[id.address()] = id;
- }
-
- return ua;
-}
-
-Defaults::Defaults() :
- defaultRootTopology((const char *)ZT_DEFAULT_ROOT_TOPOLOGY,ZT_DEFAULT_ROOT_TOPOLOGY_LEN),
- rootTopologyAuthorities(_mkRootTopologyAuth()),
- v4Broadcast(((uint32_t)0xffffffff),ZT_DEFAULT_PORT)
-{
-}
-
-} // namespace ZeroTier
diff --git a/node/DeferredPackets.cpp b/node/DeferredPackets.cpp
new file mode 100644
index 00000000..923e1339
--- /dev/null
+++ b/node/DeferredPackets.cpp
@@ -0,0 +1,95 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include "Constants.hpp"
+#include "DeferredPackets.hpp"
+#include "IncomingPacket.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Node.hpp"
+
+namespace ZeroTier {
+
+DeferredPackets::DeferredPackets(const RuntimeEnvironment *renv) :
+ RR(renv),
+ _readPtr(0),
+ _writePtr(0),
+ _die(false)
+{
+}
+
+DeferredPackets::~DeferredPackets()
+{
+ _q_m.lock();
+ _die = true;
+ _q_m.unlock();
+ _q_s.post();
+}
+
+bool DeferredPackets::enqueue(IncomingPacket *pkt)
+{
+ _q_m.lock();
+ const unsigned long p = _writePtr % ZT_DEFFEREDPACKETS_MAX;
+ if (_q[p]) {
+ _q_m.unlock();
+ return false;
+ } else {
+ _q[p].setToUnsafe(pkt);
+ ++_writePtr;
+ _q_m.unlock();
+ _q_s.post();
+ return true;
+ }
+}
+
+int DeferredPackets::process()
+{
+ SharedPtr<IncomingPacket> pkt;
+
+ _q_m.lock();
+ if (_die) {
+ _q_m.unlock();
+ _q_s.post();
+ return -1;
+ }
+ while (_readPtr == _writePtr) {
+ _q_m.unlock();
+ _q_s.wait();
+ _q_m.lock();
+ if (_die) {
+ _q_m.unlock();
+ _q_s.post();
+ return -1;
+ }
+ }
+ pkt.swap(_q[_readPtr++ % ZT_DEFFEREDPACKETS_MAX]);
+ _q_m.unlock();
+
+ pkt->tryDecode(RR,true);
+ return 1;
+}
+
+} // namespace ZeroTier
diff --git a/node/DeferredPackets.hpp b/node/DeferredPackets.hpp
new file mode 100644
index 00000000..1ea65f3c
--- /dev/null
+++ b/node/DeferredPackets.hpp
@@ -0,0 +1,98 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_DEFERREDPACKETS_HPP
+#define ZT_DEFERREDPACKETS_HPP
+
+#include "Constants.hpp"
+#include "SharedPtr.hpp"
+#include "Mutex.hpp"
+#include "DeferredPackets.hpp"
+#include "BinarySemaphore.hpp"
+
+/**
+ * Maximum number of deferred packets
+ */
+#define ZT_DEFFEREDPACKETS_MAX 1024
+
+namespace ZeroTier {
+
+class IncomingPacket;
+class RuntimeEnvironment;
+
+/**
+ * Deferred packets
+ *
+ * IncomingPacket can defer its decoding this way by enqueueing itself here.
+ * When this is done, deferredDecode() is called later. This is done for
+ * operations that may be expensive to allow them to potentially be handled
+ * in the background or rate limited to maintain quality of service for more
+ * routine operations.
+ */
+class DeferredPackets
+{
+public:
+ DeferredPackets(const RuntimeEnvironment *renv);
+ ~DeferredPackets();
+
+ /**
+ * Enqueue a packet
+ *
+ * Since packets enqueue themselves, they call it with 'this' and we wrap
+ * them in a SharedPtr<>. This is safe as SharedPtr<> is introspective and
+ * supports this. This should not be called from any other code outside
+ * IncomingPacket.
+ *
+ * @param pkt Packet to process later (possibly in the background)
+ * @return False if queue is full
+ */
+ bool enqueue(IncomingPacket *pkt);
+
+ /**
+ * Wait for and then process a deferred packet
+ *
+ * If we are shutting down (in destructor), this returns -1 and should
+ * not be called again. Otherwise it returns the number of packets
+ * processed.
+ *
+ * @return Number processed or -1 if shutting down
+ */
+ int process();
+
+private:
+ SharedPtr<IncomingPacket> _q[ZT_DEFFEREDPACKETS_MAX];
+ const RuntimeEnvironment *const RR;
+ unsigned long _readPtr;
+ unsigned long _writePtr;
+ bool _die;
+ Mutex _q_m;
+ BinarySemaphore _q_s;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp
index beef1468..aee24989 100644
--- a/node/Hashtable.hpp
+++ b/node/Hashtable.hpp
@@ -103,7 +103,7 @@ public:
private:
unsigned long _idx;
Hashtable *_ht;
- Hashtable::_Bucket *_b;
+ _Bucket *_b;
};
friend class Hashtable::Iterator;
@@ -322,7 +322,6 @@ public:
b->next = _t[bidx];
_t[bidx] = b;
++_s;
-
return b->v;
}
@@ -351,7 +350,6 @@ public:
b->next = _t[bidx];
_t[bidx] = b;
++_s;
-
return b->v;
}
@@ -382,7 +380,10 @@ private:
}
static inline unsigned long _hc(const uint32_t i)
{
- // In the uint32_t case we use a simple multiplier for hashing to ensure coverage
+ return ((unsigned long)i * (unsigned long)0x9e3779b1);
+ }
+ static inline unsigned long _hc(const uint16_t i)
+ {
return ((unsigned long)i * (unsigned long)0x9e3779b1);
}
diff --git a/node/Identity.cpp b/node/Identity.cpp
index 8765da51..4611f6a5 100644
--- a/node/Identity.cpp
+++ b/node/Identity.cpp
@@ -41,7 +41,6 @@
#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17
#define ZT_IDENTITY_GEN_MEMORY 2097152
-#define ZT_IDENTITY_GEN_SALSA20_ROUNDS 20
namespace ZeroTier {
@@ -55,8 +54,8 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub
// ordinary Salsa20 is randomly seekable. This is good for a cipher
// but is not what we want for sequential memory-harndess.
memset(genmem,0,ZT_IDENTITY_GEN_MEMORY);
- Salsa20 s20(digest,256,(char *)digest + 32,ZT_IDENTITY_GEN_SALSA20_ROUNDS);
- s20.encrypt((char *)genmem,(char *)genmem,64);
+ Salsa20 s20(digest,256,(char *)digest + 32);
+ s20.encrypt20((char *)genmem,(char *)genmem,64);
for(unsigned long i=64;i<ZT_IDENTITY_GEN_MEMORY;i+=64) {
unsigned long k = i - 64;
*((uint64_t *)((char *)genmem + i)) = *((uint64_t *)((char *)genmem + k));
@@ -67,7 +66,7 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub
*((uint64_t *)((char *)genmem + i + 40)) = *((uint64_t *)((char *)genmem + k + 40));
*((uint64_t *)((char *)genmem + i + 48)) = *((uint64_t *)((char *)genmem + k + 48));
*((uint64_t *)((char *)genmem + i + 56)) = *((uint64_t *)((char *)genmem + k + 56));
- s20.encrypt((char *)genmem + i,(char *)genmem + i,64);
+ s20.encrypt20((char *)genmem + i,(char *)genmem + i,64);
}
// Render final digest using genmem as a lookup table
@@ -77,7 +76,7 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub
uint64_t tmp = ((uint64_t *)genmem)[idx2];
((uint64_t *)genmem)[idx2] = ((uint64_t *)digest)[idx1];
((uint64_t *)digest)[idx1] = tmp;
- s20.encrypt(digest,digest,64);
+ s20.encrypt20(digest,digest,64);
}
}
@@ -159,7 +158,7 @@ bool Identity::fromString(const char *str)
return false;
char *saveptr = (char *)0;
- char tmp[4096];
+ char tmp[1024];
if (!Utils::scopy(tmp,sizeof(tmp),str))
return false;
diff --git a/node/Identity.hpp b/node/Identity.hpp
index 18e67eb6..6c33e74f 100644
--- a/node/Identity.hpp
+++ b/node/Identity.hpp
@@ -38,8 +38,7 @@
#include "Address.hpp"
#include "C25519.hpp"
#include "Buffer.hpp"
-
-#define ZT_IDENTITY_MAX_BINARY_SERIALIZED_LENGTH (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN)
+#include "SHA512.hpp"
namespace ZeroTier {
@@ -93,8 +92,7 @@ public:
}
template<unsigned int C>
- Identity(const Buffer<C> &b,unsigned int startAt = 0)
- throw(std::out_of_range,std::invalid_argument) :
+ Identity(const Buffer<C> &b,unsigned int startAt = 0) :
_privateKey((C25519::Private *)0)
{
deserialize(b,startAt);
@@ -140,6 +138,21 @@ public:
inline bool hasPrivate() const throw() { return (_privateKey != (C25519::Private *)0); }
/**
+ * Compute the SHA512 hash of our private key (if we have one)
+ *
+ * @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length)
+ * @return True on success, false if no private key
+ */
+ inline bool sha512PrivateKey(void *sha) const
+ {
+ if (_privateKey) {
+ SHA512::hash(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Sign a message with this identity (private key required)
*
* @param data Data to sign
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 305232ee..cffa0b9a 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -33,7 +33,6 @@
#include "../include/ZeroTierOne.h"
#include "Constants.hpp"
-#include "Defaults.hpp"
#include "RuntimeEnvironment.hpp"
#include "IncomingPacket.hpp"
#include "Topology.hpp"
@@ -41,44 +40,63 @@
#include "Peer.hpp"
#include "NetworkController.hpp"
#include "SelfAwareness.hpp"
+#include "Salsa20.hpp"
+#include "SHA512.hpp"
+#include "World.hpp"
+#include "Cluster.hpp"
+#include "Node.hpp"
+#include "AntiRecursion.hpp"
+#include "DeferredPackets.hpp"
namespace ZeroTier {
-bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
+bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred)
{
+ const Address sourceAddress(source());
try {
if ((cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
- // Unencrypted HELLOs are handled here since they are used to
- // populate our identity cache in the first place. _doHELLO() is special
- // in that it contains its own authentication logic.
- return _doHELLO(RR);
+ // Unencrypted HELLOs require some potentially expensive verification, so
+ // do this in the background if background processing is enabled.
+ if ((RR->dpEnabled > 0)&&(!deferred)) {
+ RR->dp->enqueue(this);
+ return true; // 'handled' via deferring to background thread(s)
+ } else {
+ // A null pointer for peer to _doHELLO() tells it to run its own
+ // special internal authentication logic. This is done for unencrypted
+ // HELLOs to learn new identities, etc.
+ SharedPtr<Peer> tmp;
+ return _doHELLO(RR,tmp);
+ }
}
- SharedPtr<Peer> peer = RR->topology->getPeer(source());
+ SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
if (peer) {
if (!dearmor(peer->key())) {
- TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),size());
+ TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),size());
return true;
}
if (!uncompress()) {
- TRACE("dropped packet from %s(%s), compressed data invalid",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped packet from %s(%s), compressed data invalid",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
- //TRACE("<< %s from %s(%s)",Packet::verbString(verb()),source().toString().c_str(),_remoteAddress.toString().c_str());
+ //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str());
- switch(verb()) {
+ const Packet::Verb v = verb();
+ switch(v) {
//case Packet::VERB_NOP:
default: // ignore unknown verbs, but if they pass auth check they are "received"
- peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),verb(),0,Packet::VERB_NOP);
+ peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP);
return true;
- case Packet::VERB_HELLO: return _doHELLO(RR);
+
+ case Packet::VERB_HELLO: return _doHELLO(RR,peer);
case Packet::VERB_ERROR: return _doERROR(RR,peer);
case Packet::VERB_OK: return _doOK(RR,peer);
case Packet::VERB_WHOIS: return _doWHOIS(RR,peer);
case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,peer);
case Packet::VERB_FRAME: return _doFRAME(RR,peer);
case Packet::VERB_EXT_FRAME: return _doEXT_FRAME(RR,peer);
+ case Packet::VERB_ECHO: return _doECHO(RR,peer);
case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,peer);
case Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return _doNETWORK_MEMBERSHIP_CERTIFICATE(RR,peer);
case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer);
@@ -88,15 +106,16 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer);
case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer);
case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer);
+ case Packet::VERB_REQUEST_PROOF_OF_WORK: return _doREQUEST_PROOF_OF_WORK(RR,peer);
}
} else {
- RR->sw->requestWhois(source());
+ RR->sw->requestWhois(sourceAddress);
return false;
}
} catch ( ... ) {
// Exceptions are more informatively caught in _do...() handlers but
// this outer try/catch will catch anything else odd.
- TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
}
@@ -108,17 +127,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
const uint64_t inRePacketId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID);
const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE];
- //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
+ //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
switch(errorCode) {
case Packet::ERROR_OBJ_NOT_FOUND:
- if (inReVerb == Packet::VERB_WHOIS) {
- if (RR->topology->isRoot(peer->identity()))
- RR->sw->cancelWhoisRequest(Address(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH));
- } else if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
+ if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
- if ((network)&&(network->controller() == source()))
+ if ((network)&&(network->controller() == peer->address()))
network->setNotFound();
}
break;
@@ -126,7 +142,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
case Packet::ERROR_UNSUPPORTED_OPERATION:
if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
- if ((network)&&(network->controller() == source()))
+ if ((network)&&(network->controller() == peer->address()))
network->setNotFound();
}
break;
@@ -147,6 +163,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
nconf->com().serialize(outp);
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
}
@@ -154,7 +171,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
- if ((network)&&(network->controller() == source()))
+ if ((network)&&(network->controller() == peer->address()))
network->setAccessDenied();
} break;
@@ -169,15 +186,13 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
}
peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb);
- } catch (std::exception &ex) {
- TRACE("dropped ERROR from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
} catch ( ... ) {
- TRACE("dropped ERROR from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
-bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
+bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer)
{
/* Note: this is the only packet ever sent in the clear, and it's also
* the only packet that we authenticate via a different path. Authentication
@@ -187,141 +202,154 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
* in the first place. */
try {
+ const uint64_t pid = packetId();
+ const Address fromAddress(source());
const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION];
const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION];
const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION);
const uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
+
Identity id;
- unsigned int destAddrPtr = id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY) + ZT_PROTO_VERB_HELLO_IDX_IDENTITY;
+ InetAddress externalSurfaceAddress;
+ uint64_t worldId = ZT_WORLD_ID_NULL;
+ uint64_t worldTimestamp = 0;
+ {
+ unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
+ if (ptr < size()) // ZeroTier One < 1.0.3 did not include physical destination address info
+ ptr += externalSurfaceAddress.deserialize(*this,ptr);
+ if ((ptr + 16) <= size()) { // older versions also did not include World IDs or timestamps
+ worldId = at<uint64_t>(ptr); ptr += 8;
+ worldTimestamp = at<uint64_t>(ptr);
+ }
+ }
if (protoVersion < ZT_PROTO_VERSION_MIN) {
TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
- if (source() != id.address()) {
- TRACE("dropped HELLO from %s(%s): identity not for sending address",source().toString().c_str(),_remoteAddress.toString().c_str());
+ if (fromAddress != id.address()) {
+ TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
- InetAddress destAddr;
- if (destAddrPtr < size()) { // ZeroTier One < 1.0.3 did not include this field
- const unsigned int destAddrType = (*this)[destAddrPtr++];
- switch(destAddrType) {
- case ZT_PROTO_DEST_ADDRESS_TYPE_IPV4:
- destAddr.set(field(destAddrPtr,4),4,at<uint16_t>(destAddrPtr + 4));
- break;
- case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6:
- destAddr.set(field(destAddrPtr,16),16,at<uint16_t>(destAddrPtr + 16));
- break;
- }
- }
-
- SharedPtr<Peer> peer(RR->topology->getPeer(id.address()));
- if (peer) {
- // We already have an identity with this address -- check for collisions
-
- if (peer->identity() != id) {
- // Identity is different from the one we already have -- address collision
-
- unsigned char key[ZT_PEER_SECRET_KEY_LENGTH];
- if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) {
- if (dearmor(key)) { // ensure packet is authentic, otherwise drop
- RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress);
- TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str());
- Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR);
- outp.append((unsigned char)Packet::VERB_HELLO);
- outp.append(packetId());
- outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
- outp.armor(key,true);
- RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ if (!peer) { // peer == NULL is the normal case here
+ peer = RR->topology->getPeer(id.address());
+ if (peer) {
+ // We already have an identity with this address -- check for collisions
+
+ if (peer->identity() != id) {
+ // Identity is different from the one we already have -- address collision
+
+ unsigned char key[ZT_PEER_SECRET_KEY_LENGTH];
+ if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) {
+ if (dearmor(key)) { // ensure packet is authentic, otherwise drop
+ TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_HELLO);
+ outp.append((uint64_t)pid);
+ outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
+ outp.armor(key,true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } else {
+ TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
} else {
- RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress);
- TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_remoteAddress.toString().c_str());
}
+
+ return true;
} else {
- RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress);
- TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_remoteAddress.toString().c_str());
- }
+ // Identity is the same as the one we already have -- check packet integrity
- return true;
+ if (!dearmor(peer->key())) {
+ TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+
+ // Continue at // VALID
+ }
} else {
- // Identity is the same as the one we already have -- check packet integrity
+ // We don't already have an identity with this address -- validate and learn it
+
+ // Check identity proof of work
+ if (!id.locallyValidate()) {
+ TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
- if (!dearmor(peer->key())) {
- RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress);
+ // Check packet integrity and authentication
+ SharedPtr<Peer> newPeer(new Peer(RR->identity,id));
+ if (!dearmor(newPeer->key())) {
TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
+ peer = RR->topology->addPeer(newPeer);
// Continue at // VALID
}
- } else {
- // We don't already have an identity with this address -- validate and learn it
-
- // Check identity proof of work
- if (!id.locallyValidate()) {
- RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress);
- TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_remoteAddress.toString().c_str());
- return true;
- }
-
- // Check packet integrity and authentication
- SharedPtr<Peer> newPeer(new Peer(RR->identity,id));
- if (!dearmor(newPeer->key())) {
- RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress);
- TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
- return true;
- }
-
- peer = RR->topology->addPeer(newPeer);
- // Continue at // VALID
+ // VALID -- if we made it here, packet passed identity and authenticity checks!
}
- // VALID -- continues here
-
- peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP);
- peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision);
-
- bool trusted = false;
- if (RR->topology->isRoot(id)) {
- RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision);
- trusted = true;
- }
- if (destAddr)
- RR->sa->iam(id.address(),_remoteAddress,destAddr,trusted,RR->node->now());
+ if (externalSurfaceAddress)
+ RR->sa->iam(id.address(),_remoteAddress,externalSurfaceAddress,RR->topology->isRoot(id),RR->node->now());
Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK);
-
outp.append((unsigned char)Packet::VERB_HELLO);
- outp.append(packetId());
- outp.append(timestamp);
+ outp.append((uint64_t)pid);
+ outp.append((uint64_t)timestamp);
outp.append((unsigned char)ZT_PROTO_VERSION);
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
+ if (protoVersion >= 5) {
+ _remoteAddress.serialize(outp);
+ } else {
+ /* LEGACY COMPATIBILITY HACK:
+ *
+ * For a while now (since 1.0.3), ZeroTier has recognized changes in
+ * its network environment empirically by examining its external network
+ * address as reported by trusted peers. In versions prior to 1.1.0
+ * (protocol version < 5), they did this by saving a snapshot of this
+ * information (in SelfAwareness.hpp) keyed by reporting device ID and
+ * address type.
+ *
+ * This causes problems when clustering is combined with symmetric NAT.
+ * Symmetric NAT remaps ports, so different endpoints in a cluster will
+ * report back different exterior addresses. Since the old code keys
+ * this by device ID and not sending physical address and compares the
+ * entire address including port, it constantly thinks its external
+ * surface is changing and resets connections when talking to a cluster.
+ *
+ * In new code we key by sending physical address and device and we also
+ * take the more conservative position of only interpreting changes in
+ * IP address (neglecting port) as a change in network topology that
+ * necessitates a reset. But we can make older clients work here by
+ * nulling out the port field. Since this info is only used for empirical
+ * detection of link changes, it doesn't break anything else.
+ */
+ InetAddress tmpa(_remoteAddress);
+ tmpa.setPort(0);
+ tmpa.serialize(outp);
+ }
- switch(_remoteAddress.ss_family) {
- case AF_INET:
- outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV4);
- outp.append(_remoteAddress.rawIpData(),4);
- outp.append((uint16_t)_remoteAddress.port());
- break;
- case AF_INET6:
- outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV6);
- outp.append(_remoteAddress.rawIpData(),16);
- outp.append((uint16_t)_remoteAddress.port());
- break;
- default:
- outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_NONE);
- break;
+ if ((worldId != ZT_WORLD_ID_NULL)&&(RR->topology->worldTimestamp() > worldTimestamp)&&(worldId == RR->topology->worldId())) {
+ World w(RR->topology->world());
+ const unsigned int sizeAt = outp.size();
+ outp.addSize(2); // make room for 16-bit size field
+ w.serialize(outp,false);
+ outp.setAt<uint16_t>(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2)));
+ } else {
+ outp.append((uint16_t)0); // no world update needed
}
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
- } catch (std::exception &ex) {
- TRACE("dropped HELLO from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
+
+ peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision);
+ peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP);
} catch ( ... ) {
TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
@@ -345,46 +373,43 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION];
const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION);
- InetAddress destAddr;
- unsigned int destAddrPtr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; // dest address, if present, will start after 16-bit revision
- if (destAddrPtr < size()) { // ZeroTier One < 1.0.3 did not include this field
- const unsigned int destAddrType = (*this)[destAddrPtr++];
- switch(destAddrType) {
- case ZT_PROTO_DEST_ADDRESS_TYPE_IPV4:
- destAddr.set(field(destAddrPtr,4),4,at<uint16_t>(destAddrPtr + 4));
- break;
- case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6:
- destAddr.set(field(destAddrPtr,16),16,at<uint16_t>(destAddrPtr + 16));
- break;
- }
- }
-
if (vProto < ZT_PROTO_VERSION_MIN) {
TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
- TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency,((destAddr) ? destAddr.toString().c_str() : "(none)"));
+ const bool trusted = RR->topology->isRoot(peer->identity());
+
+ InetAddress externalSurfaceAddress;
+ unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2;
+ if (ptr < size()) // ZeroTier One < 1.0.3 did not include this field
+ ptr += externalSurfaceAddress.deserialize(*this,ptr);
+ if ((trusted)&&((ptr + 2) <= size())) { // older versions also did not include this field, and right now we only use if from a root
+ World worldUpdate;
+ const unsigned int worldLen = at<uint16_t>(ptr); ptr += 2;
+ if (worldLen > 0) {
+ World w;
+ w.deserialize(*this,ptr);
+ RR->topology->worldUpdateIfValid(w);
+ }
+ }
+
+ TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)"));
peer->addDirectLatencyMeasurment(latency);
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
- bool trusted = false;
- if (RR->topology->isRoot(peer->identity())) {
- RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision);
- trusted = true;
- }
- if (destAddr)
- RR->sa->iam(peer->address(),_remoteAddress,destAddr,trusted,RR->node->now());
+ if (externalSurfaceAddress)
+ RR->sa->iam(peer->address(),_remoteAddress,externalSurfaceAddress,trusted,RR->node->now());
} break;
case Packet::VERB_WHOIS: {
- /* Right now only root servers are allowed to send OK(WHOIS) to prevent
- * poisoning attacks. Further decentralization will require some other
- * kind of trust mechanism. */
if (RR->topology->isRoot(peer->identity())) {
const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY);
- if (id.locallyValidate())
+ // Right now we can skip this since OK(WHOIS) is only accepted from
+ // roots. In the future it should be done if we query less trusted
+ // sources.
+ //if (id.locallyValidate())
RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr<Peer>(new Peer(RR->identity,id))));
}
} break;
@@ -438,10 +463,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
}
peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb);
- } catch (std::exception &ex) {
- TRACE("dropped OK from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
} catch ( ... ) {
- TRACE("dropped OK from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -450,22 +473,20 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer>
{
try {
if (payloadLength() == ZT_ADDRESS_LENGTH) {
- const SharedPtr<Peer> queried(RR->topology->getPeer(Address(payload(),ZT_ADDRESS_LENGTH)));
+ Identity queried(RR->topology->getIdentity(Address(payload(),ZT_ADDRESS_LENGTH)));
if (queried) {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_WHOIS);
outp.append(packetId());
- queried->identity().serialize(outp,false);
+ queried.serialize(outp,false);
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} else {
- Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
- outp.append((unsigned char)Packet::VERB_WHOIS);
- outp.append(packetId());
- outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
- outp.append(payload(),ZT_ADDRESS_LENGTH);
- outp.armor(peer->key(),true);
- RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->sendDistributedQuery(*this);
+#endif
}
} else {
TRACE("dropped WHOIS from %s(%s): missing or invalid address",source().toString().c_str(),_remoteAddress.toString().c_str());
@@ -480,24 +501,27 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer>
bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
{
try {
- const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
- const SharedPtr<Peer> withPeer(RR->topology->getPeer(with));
- if (withPeer) {
- const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
- const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
- if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
- InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
- TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
- peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
- RR->sw->rendezvous(withPeer,_localAddress,atAddr);
+ if (RR->topology->isUpstream(peer->identity())) {
+ const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+ const SharedPtr<Peer> withPeer(RR->topology->getPeer(with));
+ if (withPeer) {
+ const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
+ const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
+ if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
+ InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
+ TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
+ peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
+ RR->sw->rendezvous(withPeer,_localAddress,atAddr);
+ } else {
+ TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
} else {
- TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ RR->sw->requestWhois(with);
+ TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str());
}
} else {
- TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str());
+ TRACE("ignored RENDEZVOUS from %s(%s): not a root server or a network relay",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
}
- } catch (std::exception &ex) {
- TRACE("dropped RENDEZVOUS from %s(%s): %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
} catch ( ... ) {
TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
}
@@ -530,10 +554,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer>
} else {
TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
}
- } catch (std::exception &ex) {
- TRACE("dropped FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
} catch ( ... ) {
- TRACE("dropped FRAME from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -547,15 +569,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS];
unsigned int comLen = 0;
- bool comFailed = false;
if ((flags & 0x01) != 0) {
CertificateOfMembership com;
comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM);
- if (!peer->validateAndSetNetworkMembershipCertificate(RR,network->id(),com))
- comFailed = true;
+ peer->validateAndSetNetworkMembershipCertificate(RR,network->id(),com);
}
- if ((comFailed)||(!network->isAllowed(peer))) {
+ if (!network->isAllowed(peer)) {
TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),network->id());
_sendErrorNeedCertificate(RR,peer,network->id());
return true;
@@ -605,10 +625,25 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
} else {
TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
}
- } catch (std::exception &ex) {
- TRACE("dropped EXT_FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
} catch ( ... ) {
- TRACE("dropped EXT_FRAME from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const uint64_t pid = packetId();
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_ECHO);
+ outp.append((uint64_t)pid);
+ outp.append(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -619,14 +654,15 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared
const uint64_t now = RR->node->now();
// Iterate through 18-byte network,MAC,ADI tuples
- for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr<size();ptr+=18)
- RR->mc->add(now,at<uint64_t>(ptr),MulticastGroup(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14)),peer->address());
+ for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr<size();ptr+=18) {
+ const uint64_t nwid = at<uint64_t>(ptr);
+ const MulticastGroup group(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14));
+ RR->mc->add(now,nwid,group,peer->address());
+ }
peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP);
- } catch (std::exception &ex) {
- TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
} catch ( ... ) {
- TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -643,10 +679,8 @@ bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment
}
peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP);
- } catch (std::exception &ex) {
- TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
} catch ( ... ) {
- TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -680,9 +714,10 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
outp.append(netconfStr.data(),(unsigned int)netconfStr.length());
outp.compress();
outp.armor(peer->key(),true);
- if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) {
+ if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { // sanity check
TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length());
} else {
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
}
@@ -695,6 +730,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
outp.append(nwid);
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} break;
@@ -705,6 +741,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_);
outp.append(nwid);
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} break;
@@ -727,12 +764,11 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
outp.append(nwid);
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
- } catch (std::exception &exc) {
- TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
} catch ( ... ) {
- TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -749,10 +785,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons
ptr += 8;
}
peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP);
- } catch (std::exception &exc) {
- TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
} catch ( ... ) {
- TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -773,17 +807,22 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar
outp.append(nwid);
mg.mac().appendTo(outp);
outp.append((uint32_t)mg.adi());
- if (RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit)) {
+ const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit);
+ if (gatheredLocally) {
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
+
+#ifdef ZT_ENABLE_CLUSTER
+ if ((RR->cluster)&&(gatheredLocally < gatherLimit))
+ RR->cluster->sendDistributedQuery(*this);
+#endif
}
peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP);
- } catch (std::exception &exc) {
- TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
} catch ( ... ) {
- TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -865,16 +904,15 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
outp.append((unsigned char)0x02); // flag 0x02 = contains gather results
if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) {
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
}
} // else ignore -- not a member of this network
peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP);
- } catch (std::exception &exc) {
- TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
} catch ( ... ) {
- TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -882,11 +920,23 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
{
try {
+ const uint64_t now = RR->node->now();
+
+ // First, subject this to a rate limit
+ if (!peer->shouldRespondToDirectPathPush(now)) {
+ TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+
+ // Second, limit addresses by scope and type
+ uint8_t countPerScope[ZT_INETADDRESS_MAX_SCOPE+1][2]; // [][0] is v4, [][1] is v6
+ memset(countPerScope,0,sizeof(countPerScope));
+
unsigned int count = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD);
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2;
while (count--) { // if ptr overflows Buffer will throw
- // TODO: properly handle blacklisting, support other features... see Packet.hpp.
+ // TODO: some flags are not yet implemented
unsigned int flags = (*this)[ptr++];
unsigned int extLen = at<uint16_t>(ptr); ptr += 2;
@@ -897,25 +947,33 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
switch(addrType) {
case 4: {
InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4));
- if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) {
- TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
- peer->attemptToContactAt(RR,_localAddress,a,RR->node->now());
+ if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) {
+ if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
+ TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
+ peer->sendHELLO(RR,_localAddress,a,now);
+ } else {
+ TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
+ }
}
} break;
case 6: {
InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
- if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) {
- TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
- peer->attemptToContactAt(RR,_localAddress,a,RR->node->now());
+ if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) {
+ if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
+ TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
+ peer->sendHELLO(RR,_localAddress,a,now);
+ } else {
+ TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
+ }
}
} break;
}
ptr += addrLen;
}
- } catch (std::exception &exc) {
- TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
+
+ peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -1021,7 +1079,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
remainingHopsPtr += ZT_ADDRESS_LENGTH;
SharedPtr<Peer> nhp(RR->topology->getPeer(nextHop[h]));
if (nhp) {
- RemotePath *const rp = nhp->getBestPath(now);
+ Path *const rp = nhp->getBestPath(now);
if (rp)
nextHopBestPathAddress[h] = rp->address();
}
@@ -1044,6 +1102,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
outp.append((uint16_t)0); // error code, currently unused
outp.append((uint64_t)0); // flags, currently unused
outp.append((uint64_t)packetId());
+ peer->address().appendTo(outp);
outp.append((uint8_t)hops());
_localAddress.serialize(outp);
_remoteAddress.serialize(outp);
@@ -1071,21 +1130,194 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr);
for(unsigned int h=0;h<breadth;++h) {
- outp.newInitializationVector();
- outp.setDestination(nextHop[h]);
- RR->sw->send(outp,true,originatorCredentialNetworkId);
+ if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid
+ outp.newInitializationVector();
+ outp.setDestination(nextHop[h]);
+ RR->sw->send(outp,true,originatorCredentialNetworkId);
+ }
}
}
- } catch (std::exception &exc) {
- TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
+
+ peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
{
+ try {
+ ZT_CircuitTestReport report;
+ memset(&report,0,sizeof(report));
+
+ report.current = peer->address().toInt();
+ report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
+ report.testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 8);
+ report.timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
+ report.remoteTimestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 16);
+ report.sourcePacketId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 44);
+ report.flags = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 36);
+ report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58
+ report.errorCode = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 34);
+ report.vendor = (enum ZT_Vendor)((*this)[ZT_PACKET_IDX_PAYLOAD + 24]);
+ report.protocolVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 25];
+ report.majorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 26];
+ report.minorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 27];
+ report.revision = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 28);
+ report.platform = (enum ZT_Platform)at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 30);
+ report.architecture = (enum ZT_Architecture)at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 32);
+
+ const unsigned int receivedOnLocalAddressLen = reinterpret_cast<InetAddress *>(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58);
+ const unsigned int receivedFromRemoteAddressLen = reinterpret_cast<InetAddress *>(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen);
+
+ unsigned int nhptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen;
+ nhptr += at<uint16_t>(nhptr) + 2; // add "additional field" length, which right now will be zero
+
+ report.nextHopCount = (*this)[nhptr++];
+ if (report.nextHopCount > ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) // sanity check, shouldn't be possible
+ report.nextHopCount = ZT_CIRCUIT_TEST_MAX_HOP_BREADTH;
+ for(unsigned int h=0;h<report.nextHopCount;++h) {
+ report.nextHops[h].address = Address(field(nhptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); nhptr += ZT_ADDRESS_LENGTH;
+ nhptr += reinterpret_cast<InetAddress *>(&(report.nextHops[h].physicalAddress))->deserialize(*this,nhptr);
+ }
+
+ RR->node->postCircuitTestReport(&report);
+ } catch ( ... ) {
+ TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ // Right now this is only allowed from root servers -- may be allowed from controllers and relays later.
+ if (RR->topology->isRoot(peer->identity())) {
+ const uint64_t pid = packetId();
+ const unsigned int difficulty = (*this)[ZT_PACKET_IDX_PAYLOAD + 1];
+ const unsigned int challengeLength = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 2);
+ if (challengeLength > ZT_PROTO_MAX_PACKET_LENGTH)
+ return true; // sanity check, drop invalid size
+ const unsigned char *challenge = field(ZT_PACKET_IDX_PAYLOAD + 4,challengeLength);
+
+ switch((*this)[ZT_PACKET_IDX_PAYLOAD]) {
+
+ // Salsa20/12+SHA512 hashcash
+ case 0x01: {
+ if (difficulty <= 14) {
+ unsigned char result[16];
+ computeSalsa2012Sha512ProofOfWork(difficulty,challenge,challengeLength,result);
+ TRACE("PROOF_OF_WORK computed for %s: difficulty==%u, challengeLength==%u, result: %.16llx%.16llx",peer->address().toString().c_str(),difficulty,challengeLength,Utils::ntoh(*(reinterpret_cast<const uint64_t *>(result))),Utils::ntoh(*(reinterpret_cast<const uint64_t *>(result + 8))));
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK);
+ outp.append(pid);
+ outp.append((uint16_t)sizeof(result));
+ outp.append(result,sizeof(result));
+ outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } else {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK);
+ outp.append(pid);
+ outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST);
+ outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ }
+ } break;
+
+ default:
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ break;
+ }
+
+ peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP);
+ } else {
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ } catch ( ... ) {
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+void IncomingPacket::computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16])
+{
+ unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function
+ char candidatebuf[ZT_PROTO_MAX_PACKET_LENGTH + 256];
+ unsigned char shabuf[ZT_SHA512_DIGEST_LEN];
+ const uint64_t s20iv = 0; // zero IV for Salsa20
+ char *const candidate = (char *)(( ((uintptr_t)&(candidatebuf[0])) | 0xf ) + 1); // align to 16-byte boundary to ensure that uint64_t type punning of initial nonce is okay
+ Salsa20 s20;
+ unsigned int d;
+ unsigned char *p;
+
+ Utils::getSecureRandom(candidate,16);
+ memcpy(candidate + 16,challenge,challengeLength);
+
+ if (difficulty > 512)
+ difficulty = 512; // sanity check
+
+try_salsa2012sha512_again:
+ ++*(reinterpret_cast<volatile uint64_t *>(candidate));
+
+ SHA512::hash(shabuf,candidate,16 + challengeLength);
+ s20.init(shabuf,256,&s20iv);
+ memset(salsabuf,0,sizeof(salsabuf));
+ s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf));
+ SHA512::hash(shabuf,salsabuf,sizeof(salsabuf));
+
+ d = difficulty;
+ p = shabuf;
+ while (d >= 8) {
+ if (*(p++))
+ goto try_salsa2012sha512_again;
+ d -= 8;
+ }
+ if (d > 0) {
+ if ( ((((unsigned int)*p) << d) & 0xff00) != 0 )
+ goto try_salsa2012sha512_again;
+ }
+
+ memcpy(result,candidate,16);
+}
+
+bool IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(unsigned int difficulty,const void *challenge,unsigned int challengeLength,const unsigned char proposedResult[16])
+{
+ unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function
+ char candidate[ZT_PROTO_MAX_PACKET_LENGTH + 256];
+ unsigned char shabuf[ZT_SHA512_DIGEST_LEN];
+ const uint64_t s20iv = 0; // zero IV for Salsa20
+ Salsa20 s20;
+ unsigned int d;
+ unsigned char *p;
+
+ if (difficulty > 512)
+ difficulty = 512; // sanity check
+
+ memcpy(candidate,proposedResult,16);
+ memcpy(candidate + 16,challenge,challengeLength);
+
+ SHA512::hash(shabuf,candidate,16 + challengeLength);
+ s20.init(shabuf,256,&s20iv);
+ memset(salsabuf,0,sizeof(salsabuf));
+ s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf));
+ SHA512::hash(shabuf,salsabuf,sizeof(salsabuf));
+
+ d = difficulty;
+ p = shabuf;
+ while (d >= 8) {
+ if (*(p++))
+ return false;
+ d -= 8;
+ }
+ if (d > 0) {
+ if ( ((((unsigned int)*p) << d) & 0xff00) != 0 )
+ return false;
+ }
+
return true;
}
@@ -1097,6 +1329,7 @@ void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,cons
outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
outp.append(nwid);
outp.armor(peer->key(),true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp
index 06220c4b..7fb7dbd3 100644
--- a/node/IncomingPacket.hpp
+++ b/node/IncomingPacket.hpp
@@ -93,30 +93,59 @@ public:
* about whether the packet was valid. A rejection is 'complete.'
*
* Once true is returned, this must not be called again. The packet's state
- * may no longer be valid.
+ * may no longer be valid. The only exception is deferred decoding. In this
+ * case true is returned to indicate to the normal decode path that it is
+ * finished with the packet. The packet will have added itself to the
+ * deferred queue and will expect tryDecode() to be called one more time
+ * with deferred set to true.
+ *
+ * Deferred decoding is performed by DeferredPackets.cpp and should not be
+ * done elsewhere. Under deferred decoding packets only get one shot and
+ * so the return value of tryDecode() is ignored.
*
* @param RR Runtime environment
+ * @param deferred If true, this is a deferred decode and the return is ignored
* @return True if decoding and processing is complete, false if caller should try again
- * @throws std::out_of_range Range error processing packet (should be discarded)
- * @throws std::runtime_error Other error processing packet (should be discarded)
*/
- bool tryDecode(const RuntimeEnvironment *RR);
+ bool tryDecode(const RuntimeEnvironment *RR,bool deferred);
/**
* @return Time of packet receipt / start of decode
*/
inline uint64_t receiveTime() const throw() { return _receiveTime; }
+ /**
+ * Compute the Salsa20/12+SHA512 proof of work function
+ *
+ * @param difficulty Difficulty in bits (max: 64)
+ * @param challenge Challenge string
+ * @param challengeLength Length of challenge in bytes (max allowed: ZT_PROTO_MAX_PACKET_LENGTH)
+ * @param result Buffer to fill with 16-byte result
+ */
+ static void computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16]);
+
+ /**
+ * Verify the result of Salsa20/12+SHA512 proof of work
+ *
+ * @param difficulty Difficulty in bits (max: 64)
+ * @param challenge Challenge bytes
+ * @param challengeLength Length of challenge in bytes (max allowed: ZT_PROTO_MAX_PACKET_LENGTH)
+ * @param proposedResult Result supplied by client
+ * @return True if result is valid
+ */
+ static bool testSalsa2012Sha512ProofOfWorkResult(unsigned int difficulty,const void *challenge,unsigned int challengeLength,const unsigned char proposedResult[16]);
+
private:
// These are called internally to handle packet contents once it has
// been authenticated, decrypted, decompressed, and classified.
bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
- bool _doHELLO(const RuntimeEnvironment *RR);
+ bool _doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer); // can be called with NULL peer, while all others cannot
bool _doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doFRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
@@ -126,6 +155,7 @@ private:
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
// Send an ERROR_NEED_MEMBERSHIP_CERTIFICATE to a peer indicating that an updated cert is needed to communicate
void _sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer,uint64_t nwid);
diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp
index e542f0d4..f35eb9c3 100644
--- a/node/InetAddress.cpp
+++ b/node/InetAddress.cpp
@@ -77,14 +77,12 @@ InetAddress::IpScope InetAddress::ipScope() const
if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16
break;
case 0xff: return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
- default:
- switch(ip >> 28) {
- case 0xe: return IP_SCOPE_MULTICAST; // 224.0.0.0/4
- case 0xf: return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
- default: return IP_SCOPE_GLOBAL; // everything else
- }
- break;
}
+ switch(ip >> 28) {
+ case 0xe: return IP_SCOPE_MULTICAST; // 224.0.0.0/4
+ case 0xf: return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
+ }
+ return IP_SCOPE_GLOBAL;
} break;
case AF_INET6: {
@@ -236,7 +234,6 @@ void InetAddress::fromString(const std::string &ipSlashPort)
}
InetAddress InetAddress::netmask() const
- throw()
{
InetAddress r(*this);
switch(r.ss_family) {
@@ -244,36 +241,40 @@ InetAddress InetAddress::netmask() const
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
break;
case AF_INET6: {
- unsigned char *bf = reinterpret_cast<unsigned char *>(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr);
- signed int bitsLeft = (signed int)netmaskBits();
- for(unsigned int i=0;i<16;++i) {
- if (bitsLeft > 0) {
- bf[i] |= (unsigned char)((bitsLeft >= 8) ? 0x00 : (0xff >> bitsLeft));
- bitsLeft -= 8;
- }
- }
+ uint64_t nm[2];
+ const unsigned int bits = netmaskBits();
+ nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
+ nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
+ memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
} break;
}
return r;
}
InetAddress InetAddress::broadcast() const
- throw()
+{
+ if (ss_family == AF_INET) {
+ InetAddress r(*this);
+ reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
+ return r;
+ }
+ return InetAddress();
+}
+
+InetAddress InetAddress::network() const
{
InetAddress r(*this);
switch(r.ss_family) {
case AF_INET:
- reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
+ reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
break;
case AF_INET6: {
- unsigned char *bf = reinterpret_cast<unsigned char *>(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr);
- signed int bitsLeft = (signed int)netmaskBits();
- for(unsigned int i=0;i<16;++i) {
- if (bitsLeft > 0) {
- bf[i] |= (unsigned char)((bitsLeft >= 8) ? 0x00 : (0xff >> bitsLeft));
- bitsLeft -= 8;
- }
- }
+ uint64_t nm[2];
+ const unsigned int bits = netmaskBits();
+ memcpy(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
+ nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
+ nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
+ memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
} break;
}
return r;
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index c376a032..2573e694 100644
--- a/node/InetAddress.hpp
+++ b/node/InetAddress.hpp
@@ -43,12 +43,17 @@
namespace ZeroTier {
/**
+ * Maximum integer value of enum IpScope
+ */
+#define ZT_INETADDRESS_MAX_SCOPE 7
+
+/**
* Extends sockaddr_storage with friendly C++ methods
*
* This is basically a "mixin" for sockaddr_storage. It adds methods and
* operators, but does not modify the structure. This can be cast to/from
- * sockaddr_storage and used interchangeably. Don't change this as it's
- * used in a few places.
+ * sockaddr_storage and used interchangeably. DO NOT change this by e.g.
+ * adding non-static fields, since much code depends on this identity.
*/
struct InetAddress : public sockaddr_storage
{
@@ -66,7 +71,8 @@ struct InetAddress : public sockaddr_storage
* IP address scope
*
* Note that these values are in ascending order of path preference and
- * MUST remain that way or Path must be changed to reflect.
+ * MUST remain that way or Path must be changed to reflect. Also be sure
+ * to change ZT_INETADDRESS_MAX_SCOPE if the max changes.
*/
enum IpScope
{
@@ -100,74 +106,88 @@ struct InetAddress : public sockaddr_storage
inline InetAddress &operator=(const InetAddress &a)
throw()
{
- memcpy(this,&a,sizeof(InetAddress));
+ if (&a != this)
+ memcpy(this,&a,sizeof(InetAddress));
return *this;
}
inline InetAddress &operator=(const InetAddress *a)
throw()
{
- memcpy(this,a,sizeof(InetAddress));
+ if (a != this)
+ memcpy(this,a,sizeof(InetAddress));
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage &ss)
throw()
{
- memcpy(this,&ss,sizeof(InetAddress));
+ if (reinterpret_cast<const InetAddress *>(&ss) != this)
+ memcpy(this,&ss,sizeof(InetAddress));
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage *ss)
throw()
{
- memcpy(this,ss,sizeof(InetAddress));
+ if (reinterpret_cast<const InetAddress *>(ss) != this)
+ memcpy(this,ss,sizeof(InetAddress));
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in &sa)
throw()
{
- memset(this,0,sizeof(InetAddress));
- memcpy(this,&sa,sizeof(struct sockaddr_in));
+ if (reinterpret_cast<const InetAddress *>(&sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ memcpy(this,&sa,sizeof(struct sockaddr_in));
+ }
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in *sa)
throw()
{
- memset(this,0,sizeof(InetAddress));
- memcpy(this,sa,sizeof(struct sockaddr_in));
+ if (reinterpret_cast<const InetAddress *>(sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ memcpy(this,sa,sizeof(struct sockaddr_in));
+ }
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in6 &sa)
throw()
{
- memset(this,0,sizeof(InetAddress));
- memcpy(this,&sa,sizeof(struct sockaddr_in6));
+ if (reinterpret_cast<const InetAddress *>(&sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ memcpy(this,&sa,sizeof(struct sockaddr_in6));
+ }
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in6 *sa)
throw()
{
- memset(this,0,sizeof(InetAddress));
- memcpy(this,sa,sizeof(struct sockaddr_in6));
+ if (reinterpret_cast<const InetAddress *>(sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ memcpy(this,sa,sizeof(struct sockaddr_in6));
+ }
return *this;
}
inline InetAddress &operator=(const struct sockaddr &sa)
throw()
{
- memset(this,0,sizeof(InetAddress));
- switch(sa.sa_family) {
- case AF_INET:
- memcpy(this,&sa,sizeof(struct sockaddr_in));
- break;
- case AF_INET6:
- memcpy(this,&sa,sizeof(struct sockaddr_in6));
- break;
+ if (reinterpret_cast<const InetAddress *>(&sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ switch(sa.sa_family) {
+ case AF_INET:
+ memcpy(this,&sa,sizeof(struct sockaddr_in));
+ break;
+ case AF_INET6:
+ memcpy(this,&sa,sizeof(struct sockaddr_in6));
+ break;
+ }
}
return *this;
}
@@ -175,14 +195,16 @@ struct InetAddress : public sockaddr_storage
inline InetAddress &operator=(const struct sockaddr *sa)
throw()
{
- memset(this,0,sizeof(InetAddress));
- switch(sa->sa_family) {
- case AF_INET:
- memcpy(this,sa,sizeof(struct sockaddr_in));
- break;
- case AF_INET6:
- memcpy(this,sa,sizeof(struct sockaddr_in6));
- break;
+ if (reinterpret_cast<const InetAddress *>(sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ switch(sa->sa_family) {
+ case AF_INET:
+ memcpy(this,sa,sizeof(struct sockaddr_in));
+ break;
+ case AF_INET6:
+ memcpy(this,sa,sizeof(struct sockaddr_in6));
+ break;
+ }
}
return *this;
}
@@ -281,17 +303,27 @@ struct InetAddress : public sockaddr_storage
/**
* Construct a full netmask as an InetAddress
+ *
+ * @return Netmask such as 255.255.255.0 if this address is /24 (port field will be unchanged)
*/
- InetAddress netmask() const
- throw();
+ InetAddress netmask() const;
/**
* Constructs a broadcast address from a network/netmask address
*
+ * This is only valid for IPv4 and will return a NULL InetAddress for other
+ * address families.
+ *
* @return Broadcast address (only IP portion is meaningful)
*/
- InetAddress broadcast() const
- throw();
+ InetAddress broadcast() const;
+
+ /**
+ * Return the network -- a.k.a. the IP ANDed with the netmask
+ *
+ * @return Network e.g. 10.0.1.0/24 from 10.0.1.200/24
+ */
+ InetAddress network() const;
/**
* @return True if this is an IPv4 address
@@ -304,7 +336,7 @@ struct InetAddress : public sockaddr_storage
inline bool isV6() const throw() { return (ss_family == AF_INET6); }
/**
- * @return pointer to raw IP address bytes
+ * @return pointer to raw address bytes or NULL if not available
*/
inline const void *rawIpData() const
throw()
@@ -317,27 +349,19 @@ struct InetAddress : public sockaddr_storage
}
/**
- * @return pointer to raw IP address bytes
- */
- inline void *rawIpData()
- throw()
- {
- switch(ss_family) {
- case AF_INET: return (void *)&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr);
- case AF_INET6: return (void *)(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
- default: return 0;
- }
- }
-
- /**
+ * Performs an IP-only comparison or, if that is impossible, a memcmp()
+ *
* @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses)
*/
inline bool ipsEqual(const InetAddress &a) const
{
- switch(ss_family) {
- case AF_INET: return (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr);
- case AF_INET6: return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0);
+ if (ss_family == a.ss_family) {
+ if (ss_family == AF_INET)
+ return (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr);
+ if (ss_family == AF_INET6)
+ return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0);
+ return (memcmp(this,&a,sizeof(InetAddress)) == 0);
}
return false;
}
@@ -366,7 +390,8 @@ struct InetAddress : public sockaddr_storage
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
{
- // Format is the same as in VERB_HELLO in Packet.hpp
+ // This is used in the protocol and must be the same as describe in places
+ // like VERB_HELLO in Packet.hpp.
switch(ss_family) {
case AF_INET:
b.append((uint8_t)0x04);
@@ -387,11 +412,21 @@ struct InetAddress : public sockaddr_storage
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
- unsigned int p = startAt;
memset(this,0,sizeof(InetAddress));
+ unsigned int p = startAt;
switch(b[p++]) {
case 0:
return 1;
+ case 0x01:
+ // TODO: Ethernet address (but accept for forward compatibility)
+ return 7;
+ case 0x02:
+ // TODO: Bluetooth address (but accept for forward compatibility)
+ return 7;
+ case 0x03:
+ // TODO: Other address types (but accept for forward compatibility)
+ // These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc.
+ return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length
case 0x04:
ss_family = AF_INET;
memcpy(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4); p += 4;
diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp
index 6a8d6379..fa9487ef 100644
--- a/node/Multicaster.cpp
+++ b/node/Multicaster.cpp
@@ -37,6 +37,7 @@
#include "Peer.hpp"
#include "C25519.hpp"
#include "CertificateOfMembership.hpp"
+#include "Node.hpp"
namespace ZeroTier {
@@ -77,7 +78,7 @@ void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &m
}
}
-unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Packet &appendTo,unsigned int limit) const
+unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const
{
unsigned char *p;
unsigned int added = 0,i,k,rptr,totalKnown = 0;
@@ -174,129 +175,134 @@ void Multicaster::send(
unsigned long idxbuf[8194];
unsigned long *indexes = idxbuf;
- Mutex::Lock _l(_groups_m);
- MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)];
-
- if (!gs.members.empty()) {
- // Allocate a memory buffer if group is monstrous
- if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long)))
- indexes = new unsigned long[gs.members.size()];
-
- // Generate a random permutation of member indexes
- for(unsigned long i=0;i<gs.members.size();++i)
- indexes[i] = i;
- for(unsigned long i=(unsigned long)gs.members.size()-1;i>0;--i) {
- unsigned long j = (unsigned long)RR->node->prng() % (i + 1);
- unsigned long tmp = indexes[j];
- indexes[j] = indexes[i];
- indexes[i] = tmp;
+ try {
+ Mutex::Lock _l(_groups_m);
+ MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)];
+
+ if (!gs.members.empty()) {
+ // Allocate a memory buffer if group is monstrous
+ if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long)))
+ indexes = new unsigned long[gs.members.size()];
+
+ // Generate a random permutation of member indexes
+ for(unsigned long i=0;i<gs.members.size();++i)
+ indexes[i] = i;
+ for(unsigned long i=(unsigned long)gs.members.size()-1;i>0;--i) {
+ unsigned long j = (unsigned long)RR->node->prng() % (i + 1);
+ unsigned long tmp = indexes[j];
+ indexes[j] = indexes[i];
+ indexes[i] = tmp;
+ }
}
- }
- if (gs.members.size() >= limit) {
- // Skip queue if we already have enough members to complete the send operation
- OutboundMulticast out;
-
- out.init(
- RR,
- now,
- nwid,
- com,
- limit,
- 1, // we'll still gather a little from peers to keep multicast list fresh
- src,
- mg,
- etherType,
- data,
- len);
-
- unsigned int count = 0;
-
- for(std::vector<Address>::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) {
- if (*ast != RR->identity.address()) {
- out.sendOnly(RR,*ast);
- if (++count >= limit)
- break;
+ if (gs.members.size() >= limit) {
+ // Skip queue if we already have enough members to complete the send operation
+ OutboundMulticast out;
+
+ out.init(
+ RR,
+ now,
+ nwid,
+ com,
+ limit,
+ 1, // we'll still gather a little from peers to keep multicast list fresh
+ src,
+ mg,
+ etherType,
+ data,
+ len);
+
+ unsigned int count = 0;
+
+ for(std::vector<Address>::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) {
+ if (*ast != RR->identity.address()) {
+ out.sendOnly(RR,*ast); // optimization: don't use dedup log if it's a one-pass send
+ if (++count >= limit)
+ break;
+ }
}
- }
- unsigned long idx = 0;
- while ((count < limit)&&(idx < gs.members.size())) {
- Address ma(gs.members[indexes[idx++]].address);
- if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) {
- out.sendOnly(RR,ma);
- ++count;
+ unsigned long idx = 0;
+ while ((count < limit)&&(idx < gs.members.size())) {
+ Address ma(gs.members[indexes[idx++]].address);
+ if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) {
+ out.sendOnly(RR,ma); // optimization: don't use dedup log if it's a one-pass send
+ ++count;
+ }
}
- }
- } else {
- unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1;
-
- if ((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY) {
- gs.lastExplicitGather = now;
- SharedPtr<Peer> sn(RR->topology->getBestRoot());
- if (sn) {
- TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str());
-
- const CertificateOfMembership *com = (CertificateOfMembership *)0;
- SharedPtr<NetworkConfig> nconf;
- if (sn->needsOurNetworkMembershipCertificate(nwid,now,true)) {
- SharedPtr<Network> nw(RR->node->network(nwid));
- if (nw) {
- nconf = nw->config2();
- if (nconf)
- com = &(nconf->com());
+ } else {
+ unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1;
+
+ if ((gs.members.empty())||((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY)) {
+ gs.lastExplicitGather = now;
+ SharedPtr<Peer> explicitGatherPeers[2];
+ explicitGatherPeers[0] = RR->topology->getBestRoot();
+ explicitGatherPeers[1] = RR->topology->getPeer(Network::controllerFor(nwid));
+ for(unsigned int k=0;k<2;++k) {
+ const SharedPtr<Peer> &p = explicitGatherPeers[k];
+ if (!p)
+ continue;
+ //TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str());
+
+ const CertificateOfMembership *com = (CertificateOfMembership *)0;
+ {
+ SharedPtr<Network> nw(RR->node->network(nwid));
+ if (nw) {
+ SharedPtr<NetworkConfig> nconf(nw->config2());
+ if ((nconf)&&(nconf->com())&&(nconf->isPrivate())&&(p->needsOurNetworkMembershipCertificate(nwid,now,true)))
+ com = &(nconf->com());
+ }
}
- }
- Packet outp(sn->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
- outp.append(nwid);
- outp.append((uint8_t)(com ? 0x01 : 0x00));
- mg.mac().appendTo(outp);
- outp.append((uint32_t)mg.adi());
- outp.append((uint32_t)gatherLimit);
- if (com)
- com->serialize(outp);
- outp.armor(sn->key(),true);
- sn->send(RR,outp.data(),outp.size(),now);
+ Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
+ outp.append(nwid);
+ outp.append((uint8_t)(com ? 0x01 : 0x00));
+ mg.mac().appendTo(outp);
+ outp.append((uint32_t)mg.adi());
+ outp.append((uint32_t)gatherLimit);
+ if (com)
+ com->serialize(outp);
+ RR->sw->send(outp,true,0);
+ }
+ gatherLimit = 0;
}
- gatherLimit = 0;
- }
- gs.txQueue.push_back(OutboundMulticast());
- OutboundMulticast &out = gs.txQueue.back();
-
- out.init(
- RR,
- now,
- nwid,
- com,
- limit,
- gatherLimit,
- src,
- mg,
- etherType,
- data,
- len);
-
- unsigned int count = 0;
-
- for(std::vector<Address>::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) {
- if (*ast != RR->identity.address()) {
- out.sendAndLog(RR,*ast);
- if (++count >= limit)
- break;
+ gs.txQueue.push_back(OutboundMulticast());
+ OutboundMulticast &out = gs.txQueue.back();
+
+ out.init(
+ RR,
+ now,
+ nwid,
+ com,
+ limit,
+ gatherLimit,
+ src,
+ mg,
+ etherType,
+ data,
+ len);
+
+ unsigned int count = 0;
+
+ for(std::vector<Address>::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) {
+ if (*ast != RR->identity.address()) {
+ out.sendAndLog(RR,*ast);
+ if (++count >= limit)
+ break;
+ }
}
- }
- unsigned long idx = 0;
- while ((count < limit)&&(idx < gs.members.size())) {
- Address ma(gs.members[indexes[idx++]].address);
- if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) {
- out.sendAndLog(RR,ma);
- ++count;
+ unsigned long idx = 0;
+ while ((count < limit)&&(idx < gs.members.size())) {
+ Address ma(gs.members[indexes[idx++]].address);
+ if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) {
+ out.sendAndLog(RR,ma);
+ ++count;
+ }
}
}
- }
+ } catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted
// Free allocated memory buffer if any
if (indexes != idxbuf)
diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp
index 898c4db7..8e6a7556 100644
--- a/node/Multicaster.hpp
+++ b/node/Multicaster.hpp
@@ -146,7 +146,7 @@ public:
* @return Number of addresses appended
* @throws std::out_of_range Buffer overflow writing to packet
*/
- unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Packet &appendTo,unsigned int limit) const;
+ unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const;
/**
* Get subscribers to a multicast group
diff --git a/node/Network.cpp b/node/Network.cpp
index 9ce58c63..afbe1074 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -37,6 +37,7 @@
#include "Packet.hpp"
#include "Buffer.hpp"
#include "NetworkController.hpp"
+#include "Node.hpp"
#include "../version.h"
@@ -144,7 +145,15 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg)
bool Network::tryAnnounceMulticastGroupsTo(const SharedPtr<Peer> &peer)
{
Mutex::Lock _l(_lock);
- return _tryAnnounceMulticastGroupsTo(RR->topology->rootAddresses(),_allMulticastGroups(),peer,RR->node->now());
+ if (
+ (_isAllowed(peer)) ||
+ (peer->address() == this->controller()) ||
+ (RR->topology->isRoot(peer->identity()))
+ ) {
+ _announceMulticastGroupsTo(peer->address(),_allMulticastGroups());
+ return true;
+ }
+ return false;
}
bool Network::applyConfiguration(const SharedPtr<NetworkConfig> &conf)
@@ -400,79 +409,80 @@ bool Network::_isAllowed(const SharedPtr<Peer> &peer) const
return false; // default position on any failure
}
-bool Network::_tryAnnounceMulticastGroupsTo(const std::vector<Address> &alwaysAddresses,const std::vector<MulticastGroup> &allMulticastGroups,const SharedPtr<Peer> &peer,uint64_t now) const
-{
- // assumes _lock is locked
- if (
- (_isAllowed(peer)) ||
- (peer->address() == this->controller()) ||
- (std::find(alwaysAddresses.begin(),alwaysAddresses.end(),peer->address()) != alwaysAddresses.end())
- ) {
-
- if ((_config)&&(_config->com())&&(!_config->isPublic())&&(peer->needsOurNetworkMembershipCertificate(_id,now,true))) {
- Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
- _config->com().serialize(outp);
- outp.armor(peer->key(),true);
- peer->send(RR,outp.data(),outp.size(),now);
- }
-
- {
- Packet outp(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
-
- for(std::vector<MulticastGroup>::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) {
- if ((outp.size() + 18) >= ZT_UDP_DEFAULT_PAYLOAD_MTU) {
- outp.armor(peer->key(),true);
- peer->send(RR,outp.data(),outp.size(),now);
- outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
- }
-
- // network ID, MAC, ADI
- outp.append((uint64_t)_id);
- mg->mac().appendTo(outp);
- outp.append((uint32_t)mg->adi());
- }
-
- if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) {
- outp.armor(peer->key(),true);
- peer->send(RR,outp.data(),outp.size(),now);
- }
- }
-
- return true;
- }
- return false;
-}
-
-class _AnnounceMulticastGroupsToAll
+class _GetPeersThatNeedMulticastAnnouncement
{
public:
- _AnnounceMulticastGroupsToAll(const RuntimeEnvironment *renv,Network *nw) :
+ _GetPeersThatNeedMulticastAnnouncement(const RuntimeEnvironment *renv,Network *nw) :
_now(renv->node->now()),
- RR(renv),
+ _controller(nw->controller()),
_network(nw),
- _rootAddresses(renv->topology->rootAddresses()),
- _allMulticastGroups(nw->_allMulticastGroups())
+ _rootAddresses(renv->topology->rootAddresses())
{}
-
- inline void operator()(Topology &t,const SharedPtr<Peer> &p) { _network->_tryAnnounceMulticastGroupsTo(_rootAddresses,_allMulticastGroups,p,_now); }
-
+ inline void operator()(Topology &t,const SharedPtr<Peer> &p)
+ {
+ if (
+ (_network->_isAllowed(p)) ||
+ (p->address() == _controller) ||
+ (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end())
+ ) {
+ peers.push_back(p->address());
+ }
+ }
+ std::vector<Address> peers;
private:
uint64_t _now;
- const RuntimeEnvironment *RR;
+ Address _controller;
Network *_network;
std::vector<Address> _rootAddresses;
- std::vector<MulticastGroup> _allMulticastGroups;
};
void Network::_announceMulticastGroups()
{
// Assumes _lock is locked
- _AnnounceMulticastGroupsToAll afunc(RR,this);
- RR->topology->eachPeer<_AnnounceMulticastGroupsToAll &>(afunc);
+
+ _GetPeersThatNeedMulticastAnnouncement gpfunc(RR,this);
+ RR->topology->eachPeer<_GetPeersThatNeedMulticastAnnouncement &>(gpfunc);
+
+ std::vector<MulticastGroup> allMulticastGroups(_allMulticastGroups());
+ for(std::vector<Address>::const_iterator pa(gpfunc.peers.begin());pa!=gpfunc.peers.end();++pa)
+ _announceMulticastGroupsTo(*pa,allMulticastGroups);
+}
+
+void Network::_announceMulticastGroupsTo(const Address &peerAddress,const std::vector<MulticastGroup> &allMulticastGroups) const
+{
+ // Assumes _lock is locked
+
+ // We push COMs ahead of MULTICAST_LIKE since they're used for access control -- a COM is a public
+ // credential so "over-sharing" isn't really an issue (and we only do so with roots).
+ if ((_config)&&(_config->com())&&(!_config->isPublic())) {
+ Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
+ _config->com().serialize(outp);
+ RR->sw->send(outp,true,0);
+ }
+
+ {
+ Packet outp(peerAddress,RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
+
+ for(std::vector<MulticastGroup>::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) {
+ if ((outp.size() + 18) >= ZT_UDP_DEFAULT_PAYLOAD_MTU) {
+ RR->sw->send(outp,true,0);
+ outp.reset(peerAddress,RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
+ }
+
+ // network ID, MAC, ADI
+ outp.append((uint64_t)_id);
+ mg->mac().appendTo(outp);
+ outp.append((uint32_t)mg->adi());
+ }
+
+ if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH)
+ RR->sw->send(outp,true,0);
+ }
}
std::vector<MulticastGroup> Network::_allMulticastGroups() const
{
// Assumes _lock is locked
+
std::vector<MulticastGroup> mgs;
mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1);
mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end());
@@ -481,6 +491,7 @@ std::vector<MulticastGroup> Network::_allMulticastGroups() const
mgs.push_back(Network::BROADCAST);
std::sort(mgs.begin(),mgs.end());
mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end());
+
return mgs;
}
diff --git a/node/Network.hpp b/node/Network.hpp
index f7939323..0effa8e2 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -56,7 +56,7 @@ namespace ZeroTier {
class RuntimeEnvironment;
class Peer;
-class _AnnounceMulticastGroupsToAll; // internal function object in Network.cpp
+class _GetPeersThatNeedMulticastAnnouncement;
/**
* A virtual LAN
@@ -64,7 +64,7 @@ class _AnnounceMulticastGroupsToAll; // internal function object in Network.cpp
class Network : NonCopyable
{
friend class SharedPtr<Network>;
- friend class _AnnounceMulticastGroupsToAll;
+ friend class _GetPeersThatNeedMulticastAnnouncement; // internal function object
public:
/**
@@ -344,6 +344,7 @@ private:
bool _isAllowed(const SharedPtr<Peer> &peer) const;
bool _tryAnnounceMulticastGroupsTo(const std::vector<Address> &rootAddresses,const std::vector<MulticastGroup> &allMulticastGroups,const SharedPtr<Peer> &peer,uint64_t now) const;
void _announceMulticastGroups();
+ void _announceMulticastGroupsTo(const Address &peerAddress,const std::vector<MulticastGroup> &allMulticastGroups) const;
std::vector<MulticastGroup> _allMulticastGroups() const;
const RuntimeEnvironment *RR;
diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp
index cd32600f..35e23837 100644
--- a/node/NetworkConfig.cpp
+++ b/node/NetworkConfig.cpp
@@ -55,6 +55,9 @@ SharedPtr<NetworkConfig> NetworkConfig::createTestNetworkConfig(const Address &s
if ((ip & 0x000000ff) == 0x00000000) ip ^= 0x00000001; // or .0
nc->_staticIps.push_back(InetAddress(Utils::hton(ip),8));
+ // Assign an RFC4193-compliant IPv6 address -- will never collide
+ nc->_staticIps.push_back(InetAddress::makeIpv6rfc4193(ZT_TEST_NETWORK_ID,self.toInt()));
+
return nc;
}
diff --git a/node/Node.cpp b/node/Node.cpp
index d5cc50b9..f077424b 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -46,7 +46,8 @@
#include "Address.hpp"
#include "Identity.hpp"
#include "SelfAwareness.hpp"
-#include "Defaults.hpp"
+#include "Cluster.hpp"
+#include "DeferredPackets.hpp"
const struct sockaddr_storage ZT_SOCKADDR_NULL = {0};
@@ -64,8 +65,7 @@ Node::Node(
ZT_WirePacketSendFunction wirePacketSendFunction,
ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
- ZT_EventCallback eventCallback,
- const char *overrideRootTopology) :
+ ZT_EventCallback eventCallback) :
_RR(this),
RR(&_RR),
_uPtr(uptr),
@@ -82,35 +82,33 @@ Node::Node(
_lastPingCheck(0),
_lastHousekeepingRun(0)
{
- _newestVersionSeen[0] = ZEROTIER_ONE_VERSION_MAJOR;
- _newestVersionSeen[1] = ZEROTIER_ONE_VERSION_MINOR;
- _newestVersionSeen[2] = ZEROTIER_ONE_VERSION_REVISION;
_online = false;
// Use Salsa20 alone as a high-quality non-crypto PRNG
{
char foo[32];
Utils::getSecureRandom(foo,32);
- _prng.init(foo,256,foo,8);
+ _prng.init(foo,256,foo);
memset(_prngStream,0,sizeof(_prngStream));
- _prng.encrypt(_prngStream,_prngStream,sizeof(_prngStream));
+ _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream));
}
- std::string idtmp(dataStoreGet("identity.secret"));
- if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) {
- TRACE("identity.secret not found, generating...");
- RR->identity.generate();
- idtmp = RR->identity.toString(true);
- if (!dataStorePut("identity.secret",idtmp,true))
- throw std::runtime_error("unable to write identity.secret");
- }
- RR->publicIdentityStr = RR->identity.toString(false);
- RR->secretIdentityStr = RR->identity.toString(true);
-
- idtmp = dataStoreGet("identity.public");
- if (idtmp != RR->publicIdentityStr) {
- if (!dataStorePut("identity.public",RR->publicIdentityStr,false))
- throw std::runtime_error("unable to write identity.public");
+ {
+ std::string idtmp(dataStoreGet("identity.secret"));
+ if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) {
+ TRACE("identity.secret not found, generating...");
+ RR->identity.generate();
+ idtmp = RR->identity.toString(true);
+ if (!dataStorePut("identity.secret",idtmp,true))
+ throw std::runtime_error("unable to write identity.secret");
+ }
+ RR->publicIdentityStr = RR->identity.toString(false);
+ RR->secretIdentityStr = RR->identity.toString(true);
+ idtmp = dataStoreGet("identity.public");
+ if (idtmp != RR->publicIdentityStr) {
+ if (!dataStorePut("identity.public",RR->publicIdentityStr,false))
+ throw std::runtime_error("unable to write identity.public");
+ }
}
try {
@@ -119,7 +117,9 @@ Node::Node(
RR->antiRec = new AntiRecursion();
RR->topology = new Topology(RR);
RR->sa = new SelfAwareness(RR);
+ RR->dp = new DeferredPackets(RR);
} catch ( ... ) {
+ delete RR->dp;
delete RR->sa;
delete RR->topology;
delete RR->antiRec;
@@ -128,33 +128,25 @@ Node::Node(
throw;
}
- Dictionary rt;
- if (overrideRootTopology) {
- rt.fromString(std::string(overrideRootTopology));
- } else {
- std::string rttmp(dataStoreGet("root-topology"));
- if (rttmp.length() > 0) {
- rt.fromString(rttmp);
- if (!Topology::authenticateRootTopology(rt))
- rt.clear();
- }
- if ((!rt.size())||(!rt.contains("rootservers")))
- rt.fromString(ZT_DEFAULTS.defaultRootTopology);
- }
- RR->topology->setRootServers(Dictionary(rt.get("rootservers","")));
-
postEvent(ZT_EVENT_UP);
}
Node::~Node()
{
Mutex::Lock _l(_networks_m);
- _networks.clear(); // ensure that networks are destroyed before shutdown
+
+ _networks.clear(); // ensure that networks are destroyed before shutdow
+
+ RR->dpEnabled = 0;
+ delete RR->dp;
delete RR->sa;
delete RR->topology;
delete RR->antiRec;
delete RR->mc;
delete RR->sw;
+#ifdef ZT_ENABLE_CLUSTER
+ delete RR->cluster;
+#endif
}
ZT_ResultCode Node::processWirePacket(
@@ -197,29 +189,91 @@ public:
RR(renv),
_now(now),
_relays(relays),
- _rootAddresses(RR->topology->rootAddresses())
+ _world(RR->topology->world())
{
}
- uint64_t lastReceiveFromUpstream;
+ uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay
inline void operator()(Topology &t,const SharedPtr<Peer> &p)
{
- bool isRelay = false;
- for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
- if (r->first == p->address()) {
- isRelay = true;
+ bool upstream = false;
+ InetAddress stableEndpoint4,stableEndpoint6;
+
+ // If this is a world root, pick (if possible) both an IPv4 and an IPv6 stable endpoint to use if link isn't currently alive.
+ for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
+ if (r->identity.address() == p->address()) {
+ upstream = true;
+ for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)r->stableEndpoints.size();++k) {
+ const InetAddress &addr = r->stableEndpoints[ptr++ % r->stableEndpoints.size()];
+ if (!stableEndpoint4) {
+ if (addr.ss_family == AF_INET)
+ stableEndpoint4 = addr;
+ }
+ if (!stableEndpoint6) {
+ if (addr.ss_family == AF_INET6)
+ stableEndpoint6 = addr;
+ }
+ }
break;
}
}
- if ((isRelay)||(std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end())) {
- p->doPingAndKeepalive(RR,_now);
- if (p->lastReceive() > lastReceiveFromUpstream)
- lastReceiveFromUpstream = p->lastReceive();
- } else {
- if (p->alive(_now))
- p->doPingAndKeepalive(RR,_now);
+ if (!upstream) {
+ // If I am a root server, only ping other root servers -- roots don't ping "down"
+ // since that would just be a waste of bandwidth and could potentially cause route
+ // flapping in Cluster mode.
+ if (RR->topology->amRoot())
+ return;
+
+ // Check for network preferred relays, also considered 'upstream' and thus always
+ // pinged to keep links up. If they have stable addresses we will try them there.
+ for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
+ if (r->first == p->address()) {
+ if (r->second.ss_family == AF_INET)
+ stableEndpoint4 = r->second;
+ else if (r->second.ss_family == AF_INET6)
+ stableEndpoint6 = r->second;
+ upstream = true;
+ break;
+ }
+ }
+ }
+
+ if (upstream) {
+ // "Upstream" devices are roots and relays and get special treatment -- they stay alive
+ // forever and we try to keep (if available) both IPv4 and IPv6 channels open to them.
+ bool needToContactIndirect = true;
+ if (p->doPingAndKeepalive(RR,_now,AF_INET)) {
+ needToContactIndirect = false;
+ } else {
+ if (stableEndpoint4) {
+ needToContactIndirect = false;
+ p->sendHELLO(RR,InetAddress(),stableEndpoint4,_now);
+ }
+ }
+ if (p->doPingAndKeepalive(RR,_now,AF_INET6)) {
+ needToContactIndirect = false;
+ } else {
+ if (stableEndpoint6) {
+ needToContactIndirect = false;
+ p->sendHELLO(RR,InetAddress(),stableEndpoint6,_now);
+ }
+ }
+
+ if (needToContactIndirect) {
+ // If this is an upstream and we have no stable endpoint for either IPv4 or IPv6,
+ // send a NOP indirectly if possible to see if we can get to this peer in any
+ // way whatsoever. This will e.g. find network preferred relays that lack
+ // stable endpoints by using root servers.
+ Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP);
+ RR->sw->send(outp,true,0);
+ }
+
+ lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream);
+ } else if (p->activelyTransferringFrames(_now)) {
+ // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently
+ p->doPingAndKeepalive(RR,_now,0);
}
}
@@ -227,7 +281,7 @@ private:
const RuntimeEnvironment *RR;
uint64_t _now;
const std::vector< std::pair<Address,InetAddress> > &_relays;
- std::vector<Address> _rootAddresses;
+ World _world;
};
ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
@@ -259,24 +313,13 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB
for(std::vector< SharedPtr<Network> >::const_iterator n(needConfig.begin());n!=needConfig.end();++n)
(*n)->requestConfiguration();
- // Attempt to contact network preferred relays that we don't have direct links to
- std::sort(networkRelays.begin(),networkRelays.end());
- networkRelays.erase(std::unique(networkRelays.begin(),networkRelays.end()),networkRelays.end());
- for(std::vector< std::pair<Address,InetAddress> >::const_iterator nr(networkRelays.begin());nr!=networkRelays.end();++nr) {
- if (nr->second) {
- SharedPtr<Peer> rp(RR->topology->getPeer(nr->first));
- if ((rp)&&(!rp->hasActiveDirectPath(now)))
- rp->attemptToContactAt(RR,InetAddress(),nr->second,now);
- }
- }
-
- // Ping living or root server/relay peers
+ // Do pings and keepalives
_PingPeersThatNeedPing pfunc(RR,now,networkRelays);
RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc);
// Update online status, post status change as event
- bool oldOnline = _online;
- _online = ((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT);
+ const bool oldOnline = _online;
+ _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot()));
if (oldOnline != _online)
postEvent(_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
} catch ( ... ) {
@@ -298,7 +341,18 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB
}
try {
- *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY);
+#ifdef ZT_ENABLE_CLUSTER
+ // If clustering is enabled we have to call cluster->doPeriodicTasks() very often, so we override normal timer deadline behavior
+ if (RR->cluster) {
+ RR->sw->doTimerTasks(now);
+ RR->cluster->doPeriodicTasks();
+ *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate
+ } else {
+#endif
+ *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY);
+#ifdef ZT_ENABLE_CLUSTER
+ }
+#endif
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
@@ -355,6 +409,8 @@ uint64_t Node::address() const
void Node::status(ZT_NodeStatus *status) const
{
status->address = RR->identity.address().toInt();
+ status->worldId = RR->topology->worldId();
+ status->worldTimestamp = RR->topology->worldTimestamp();
status->publicIdentity = RR->publicIdentityStr.c_str();
status->secretIdentity = RR->secretIdentityStr.c_str();
status->online = _online ? 1 : 0;
@@ -389,14 +445,13 @@ ZT_PeerList *Node::peers() const
p->latency = pi->second->latency();
p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF;
- std::vector<RemotePath> paths(pi->second->paths());
- RemotePath *bestPath = pi->second->getBestPath(_now);
+ std::vector<Path> paths(pi->second->paths());
+ Path *bestPath = pi->second->getBestPath(_now);
p->pathCount = 0;
- for(std::vector<RemotePath>::iterator path(paths.begin());path!=paths.end();++path) {
+ for(std::vector<Path>::iterator path(paths.begin());path!=paths.end();++path) {
memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage));
p->paths[p->pathCount].lastSend = path->lastSend();
p->paths[p->pathCount].lastReceive = path->lastReceived();
- p->paths[p->pathCount].fixed = path->fixed() ? 1 : 0;
p->paths[p->pathCount].active = path->active(_now) ? 1 : 0;
p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0;
++p->pathCount;
@@ -441,11 +496,11 @@ void Node::freeQueryResult(void *qr)
::free(qr);
}
-int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust)
+int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr)
{
if (Path::isAddressValidForPath(*(reinterpret_cast<const InetAddress *>(addr)))) {
Mutex::Lock _l(_directPaths_m);
- _directPaths.push_back(Path(*(reinterpret_cast<const InetAddress *>(addr)),metric,(Path::Trust)trust));
+ _directPaths.push_back(*(reinterpret_cast<const InetAddress *>(addr)));
std::sort(_directPaths.begin(),_directPaths.end());
_directPaths.erase(std::unique(_directPaths.begin(),_directPaths.end()),_directPaths.end());
return 1;
@@ -482,7 +537,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)
outp.append((uint16_t)0);
C25519::Signature sig(RR->identity.sign(reinterpret_cast<const char *>(outp.data()) + ZT_PACKET_IDX_PAYLOAD,outp.size() - ZT_PACKET_IDX_PAYLOAD));
outp.append((uint16_t)sig.size());
- outp.append(sig.data,sig.size());
+ outp.append(sig.data,(unsigned int)sig.size());
outp.append((uint16_t)0); // originator doesn't need an extra credential, since it's the originator
for(unsigned int h=1;h<test->hopCount;++h) {
outp.append((uint8_t)0);
@@ -494,7 +549,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)
for(unsigned int a=0;a<test->hops[0].breadth;++a) {
outp.newInitializationVector();
outp.setDestination(Address(test->hops[0].addresses[a]));
- RR->sw->send(outp,true,test->credentialNetworkId);
+ RR->sw->send(outp,true,0);
}
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet
@@ -522,13 +577,93 @@ void Node::circuitTestEnd(ZT_CircuitTest *test)
}
}
+ZT_ResultCode Node::clusterInit(
+ unsigned int myId,
+ const struct sockaddr_storage *zeroTierPhysicalEndpoints,
+ unsigned int numZeroTierPhysicalEndpoints,
+ int x,
+ int y,
+ int z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ return ZT_RESULT_ERROR_BAD_PARAMETER;
+
+ std::vector<InetAddress> eps;
+ for(unsigned int i=0;i<numZeroTierPhysicalEndpoints;++i)
+ eps.push_back(InetAddress(zeroTierPhysicalEndpoints[i]));
+ std::sort(eps.begin(),eps.end());
+ RR->cluster = new Cluster(RR,myId,eps,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg);
+
+ return ZT_RESULT_OK;
+#else
+ return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION;
+#endif
+}
+
+ZT_ResultCode Node::clusterAddMember(unsigned int memberId)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ if (!RR->cluster)
+ return ZT_RESULT_ERROR_BAD_PARAMETER;
+ RR->cluster->addMember((uint16_t)memberId);
+ return ZT_RESULT_OK;
+#else
+ return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION;
+#endif
+}
+
+void Node::clusterRemoveMember(unsigned int memberId)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->removeMember((uint16_t)memberId);
+#endif
+}
+
+void Node::clusterHandleIncomingMessage(const void *msg,unsigned int len)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->handleIncomingStateMessage(msg,len);
+#endif
+}
+
+void Node::clusterStatus(ZT_ClusterStatus *cs)
+{
+ if (!cs)
+ return;
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->status(*cs);
+ else
+#endif
+ memset(cs,0,sizeof(ZT_ClusterStatus));
+}
+
+void Node::backgroundThreadMain()
+{
+ ++RR->dpEnabled;
+ for(;;) {
+ try {
+ if (RR->dp->process() < 0)
+ break;
+ } catch ( ... ) {} // sanity check -- should not throw
+ }
+ --RR->dpEnabled;
+}
+
/****************************************************************************/
/* Node methods used only within node/ */
/****************************************************************************/
std::string Node::dataStoreGet(const char *name)
{
- char buf[16384];
+ char buf[1024];
std::string r;
unsigned long olen = 0;
do {
@@ -540,16 +675,6 @@ std::string Node::dataStoreGet(const char *name)
return r;
}
-void Node::postNewerVersionIfNewer(unsigned int major,unsigned int minor,unsigned int rev)
-{
- if (Utils::compareVersion(major,minor,rev,_newestVersionSeen[0],_newestVersionSeen[1],_newestVersionSeen[2]) > 0) {
- _newestVersionSeen[0] = major;
- _newestVersionSeen[1] = minor;
- _newestVersionSeen[2] = rev;
- this->postEvent(ZT_EVENT_SAW_MORE_RECENT_VERSION,(const void *)_newestVersionSeen);
- }
-}
-
#ifdef ZT_TRACE
void Node::postTrace(const char *module,unsigned int line,const char *fmt,...)
{
@@ -587,7 +712,7 @@ uint64_t Node::prng()
{
unsigned int p = (++_prngStreamPtr % (sizeof(_prngStream) / sizeof(uint64_t)));
if (!p)
- _prng.encrypt(_prngStream,_prngStream,sizeof(_prngStream));
+ _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream));
return _prngStream[p];
}
@@ -622,12 +747,11 @@ enum ZT_ResultCode ZT_Node_new(
ZT_WirePacketSendFunction wirePacketSendFunction,
ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
- ZT_EventCallback eventCallback,
- const char *overrideRootTopology)
+ ZT_EventCallback eventCallback)
{
*node = (ZT_Node *)0;
try {
- *node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,eventCallback,overrideRootTopology));
+ *node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,eventCallback));
return ZT_RESULT_OK;
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
@@ -659,8 +783,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket(
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
- reinterpret_cast<ZeroTier::Node *>(node)->postEvent(ZT_EVENT_INVALID_PACKET,(const void *)remoteAddress);
- return ZT_RESULT_OK;
+ return ZT_RESULT_OK; // "OK" since invalid packets are simply dropped, but the system is still up
}
}
@@ -786,6 +909,22 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr)
} catch ( ... ) {}
}
+int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->addLocalInterfaceAddress(addr);
+ } catch ( ... ) {
+ return 0;
+ }
+}
+
+void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->clearLocalInterfaceAddresses();
+ } catch ( ... ) {}
+}
+
void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance)
{
try {
@@ -793,7 +932,7 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance)
} catch ( ... ) {}
}
-ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
+enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->circuitTestBegin(test,reportCallback);
@@ -809,19 +948,60 @@ void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test)
} catch ( ... ) {}
}
-int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust)
+enum ZT_ResultCode ZT_Node_clusterInit(
+ ZT_Node *node,
+ unsigned int myId,
+ const struct sockaddr_storage *zeroTierPhysicalEndpoints,
+ unsigned int numZeroTierPhysicalEndpoints,
+ int x,
+ int y,
+ int z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg)
{
try {
- return reinterpret_cast<ZeroTier::Node *>(node)->addLocalInterfaceAddress(addr,metric,trust);
+ return reinterpret_cast<ZeroTier::Node *>(node)->clusterInit(myId,zeroTierPhysicalEndpoints,numZeroTierPhysicalEndpoints,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg);
} catch ( ... ) {
- return 0;
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
-void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node)
+enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId)
{
try {
- reinterpret_cast<ZeroTier::Node *>(node)->clearLocalInterfaceAddresses();
+ return reinterpret_cast<ZeroTier::Node *>(node)->clusterAddMember(memberId);
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->clusterRemoveMember(memberId);
+ } catch ( ... ) {}
+}
+
+void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->clusterHandleIncomingMessage(msg,len);
+ } catch ( ... ) {}
+}
+
+void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->clusterStatus(cs);
+ } catch ( ... ) {}
+}
+
+void ZT_Node_backgroundThreadMain(ZT_Node *node)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->backgroundThreadMain();
} catch ( ... ) {}
}
diff --git a/node/Node.hpp b/node/Node.hpp
index 20c54471..15295139 100644
--- a/node/Node.hpp
+++ b/node/Node.hpp
@@ -71,8 +71,7 @@ public:
ZT_WirePacketSendFunction wirePacketSendFunction,
ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
- ZT_EventCallback eventCallback,
- const char *overrideRootTopology);
+ ZT_EventCallback eventCallback);
~Node();
@@ -106,15 +105,39 @@ public:
ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const;
ZT_VirtualNetworkList *networks() const;
void freeQueryResult(void *qr);
- int addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust);
+ int addLocalInterfaceAddress(const struct sockaddr_storage *addr);
void clearLocalInterfaceAddresses();
void setNetconfMaster(void *networkControllerInstance);
ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *));
void circuitTestEnd(ZT_CircuitTest *test);
+ ZT_ResultCode clusterInit(
+ unsigned int myId,
+ const struct sockaddr_storage *zeroTierPhysicalEndpoints,
+ unsigned int numZeroTierPhysicalEndpoints,
+ int x,
+ int y,
+ int z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg);
+ ZT_ResultCode clusterAddMember(unsigned int memberId);
+ void clusterRemoveMember(unsigned int memberId);
+ void clusterHandleIncomingMessage(const void *msg,unsigned int len);
+ void clusterStatus(ZT_ClusterStatus *cs);
+ void backgroundThreadMain();
// Internal functions ------------------------------------------------------
/**
+ * Convenience threadMain() for easy background thread launch
+ *
+ * This allows background threads to be launched with Thread::start
+ * that will run against this node.
+ */
+ inline void threadMain() throw() { this->backgroundThreadMain(); }
+
+ /**
* @return Time as of last call to run()
*/
inline uint64_t now() const throw() { return _now; }
@@ -126,9 +149,10 @@ public:
* @param addr Destination address
* @param data Packet data
* @param len Packet length
+ * @param ttl Desired TTL (default: 0 for unchanged/default TTL)
* @return True if packet appears to have been sent
*/
- inline bool putPacket(const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len)
+ inline bool putPacket(const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
{
return (_wirePacketSendFunction(
reinterpret_cast<ZT_Node *>(this),
@@ -136,7 +160,8 @@ public:
reinterpret_cast<const struct sockaddr_storage *>(&localAddress),
reinterpret_cast<const struct sockaddr_storage *>(&addr),
data,
- len) == 0);
+ len,
+ ttl) == 0);
}
/**
@@ -193,7 +218,7 @@ public:
/**
* @return Potential direct paths to me a.k.a. local interface addresses
*/
- inline std::vector<Path> directPaths() const
+ inline std::vector<InetAddress> directPaths() const
{
Mutex::Lock _l(_directPaths_m);
return _directPaths;
@@ -226,11 +251,6 @@ public:
*/
inline bool online() const throw() { return _online; }
- /**
- * If this version is newer than the newest we've seen, post a new version seen event
- */
- void postNewerVersionIfNewer(unsigned int major,unsigned int minor,unsigned int rev);
-
#ifdef ZT_TRACE
void postTrace(const char *module,unsigned int line,const char *fmt,...);
#endif
@@ -276,7 +296,7 @@ private:
std::vector< ZT_CircuitTest * > _circuitTests;
Mutex _circuitTests_m;
- std::vector<Path> _directPaths;
+ std::vector<InetAddress> _directPaths;
Mutex _directPaths_m;
Mutex _backgroundTasksLock;
@@ -288,7 +308,6 @@ private:
uint64_t _now;
uint64_t _lastPingCheck;
uint64_t _lastHousekeepingRun;
- unsigned int _newestVersionSeen[3]; // major, minor, revision
bool _online;
};
diff --git a/node/Packet.cpp b/node/Packet.cpp
index f69e4e79..f11ae1b8 100644
--- a/node/Packet.cpp
+++ b/node/Packet.cpp
@@ -45,7 +45,7 @@ const char *Packet::verbString(Verb v)
case VERB_RENDEZVOUS: return "RENDEZVOUS";
case VERB_FRAME: return "FRAME";
case VERB_EXT_FRAME: return "EXT_FRAME";
- case VERB_P5_MULTICAST_FRAME: return "P5_MULTICAST_FRAME";
+ case VERB_ECHO: return "ECHO";
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE";
case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST";
@@ -56,6 +56,7 @@ const char *Packet::verbString(Verb v)
case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS";
case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST";
case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT";
+ case VERB_REQUEST_PROOF_OF_WORK: return "REQUEST_PROOF_OF_WORK";
}
return "(unknown)";
}
@@ -91,14 +92,14 @@ void Packet::armor(const void *key,bool encryptPayload)
setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE);
_salsa20MangleKey((const unsigned char *)key,mangledKey);
- Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8),ZT_PROTO_SALSA20_ROUNDS);
+ Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/);
// MAC key is always the first 32 bytes of the Salsa20 key stream
// This is the same construction DJB's NaCl library uses
- s20.encrypt(ZERO_KEY,macKey,sizeof(macKey));
+ s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey));
if (encryptPayload)
- s20.encrypt(payload,payload,payloadLen);
+ s20.encrypt12(payload,payload,payloadLen);
Poly1305::compute(mac,payload,payloadLen,macKey);
memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8);
@@ -115,15 +116,15 @@ bool Packet::dearmor(const void *key)
if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) {
_salsa20MangleKey((const unsigned char *)key,mangledKey);
- Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8),ZT_PROTO_SALSA20_ROUNDS);
+ Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/);
- s20.encrypt(ZERO_KEY,macKey,sizeof(macKey));
+ s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey));
Poly1305::compute(mac,payload,payloadLen,macKey);
if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8))
return false;
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
- s20.decrypt(payload,payload,payloadLen);
+ s20.decrypt12(payload,payload,payloadLen);
return true;
} else return false; // unrecognized cipher suite
diff --git a/node/Packet.hpp b/node/Packet.hpp
index 409762c7..ef0251e3 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -46,22 +46,24 @@
#include "../ext/lz4/lz4.h"
/**
- * Protocol version -- incremented only for MAJOR changes
+ * Protocol version -- incremented only for major changes
*
* 1 - 0.2.0 ... 0.2.5
* 2 - 0.3.0 ... 0.4.5
- * * Added signature and originating peer to multicast frame
- * * Double size of multicast frame bloom filter
+ * + Added signature and originating peer to multicast frame
+ * + Double size of multicast frame bloom filter
* 3 - 0.5.0 ... 0.6.0
- * * Yet another multicast redesign
- * * New crypto completely changes key agreement cipher
- * 4 - 0.6.0 ... CURRENT
- * * New identity format based on hashcash design
- *
- * This isn't going to change again for a long time unless your
- * author wakes up again at 4am with another great idea. :P
+ * + Yet another multicast redesign
+ * + New crypto completely changes key agreement cipher
+ * 4 - 0.6.0 ... 1.0.6
+ * + New identity format based on hashcash design
+ * 5 - 1.1.0 ... CURRENT
+ * + Supports circuit test, proof of work, and echo
+ * + Supports in-band world (root server definition) updates
+ * + Clustering! (Though this will work with protocol v4 clients.)
+ * + Otherwise backward compatible with protocol v4
*/
-#define ZT_PROTO_VERSION 4
+#define ZT_PROTO_VERSION 5
/**
* Minimum supported protocol version
@@ -233,15 +235,6 @@
*/
#define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD
-// Destination address types from HELLO, OK(HELLO), and other message types
-#define ZT_PROTO_DEST_ADDRESS_TYPE_NONE 0
-#define ZT_PROTO_DEST_ADDRESS_TYPE_ZEROTIER 1 // reserved but unused
-#define ZT_PROTO_DEST_ADDRESS_TYPE_ETHERNET 2 // future use
-#define ZT_PROTO_DEST_ADDRESS_TYPE_BLUETOOTH 3 // future use
-#define ZT_PROTO_DEST_ADDRESS_TYPE_IPV4 4
-#define ZT_PROTO_DEST_ADDRESS_TYPE_LTE_DIRECT 5 // future use
-#define ZT_PROTO_DEST_ADDRESS_TYPE_IPV6 6
-
// Ephemeral key record flags
#define ZT_PROTO_EPHEMERAL_KEY_FLAG_FIPS 0x01 // future use
@@ -329,8 +322,6 @@
#define ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
-#define ZT_PROTO_VERB_WHOIS__ERROR__IDX_ZTADDRESS (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)
-
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2)
@@ -354,11 +345,11 @@ namespace ZeroTier {
* ZeroTier packet
*
* Packet format:
- * <[8] random initialization vector (doubles as 64-bit packet ID)>
+ * <[8] 64-bit random packet ID and crypto initialization vector>
* <[5] destination ZT address>
* <[5] source ZT address>
* <[1] flags/cipher (top 5 bits) and ZT hop count (last 3 bits)>
- * <[8] 8-bit MAC (currently first 8 bytes of poly1305 tag)>
+ * <[8] 64-bit MAC>
* [... -- begin encryption envelope -- ...]
* <[1] encrypted flags (top 3 bits) and verb (last 5 bits)>
* [... verb-specific payload ...]
@@ -374,6 +365,10 @@ namespace ZeroTier {
* immutable. This is because intermediate nodes can increment the hop
* count up to 7 (protocol max).
*
+ * A hop count of 7 also indicates that receiving peers should not attempt
+ * to learn direct paths from this packet. (Right now direct paths are only
+ * learned from direct packets anyway.)
+ *
* http://tonyarcieri.com/all-the-crypto-code-youve-ever-written-is-probably-broken
*
* For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever
@@ -530,10 +525,13 @@ public:
*/
enum Verb /* Max value: 32 (5 bits) */
{
- /* No operation, payload ignored, no reply */
+ /**
+ * No operation (ignored, no reply)
+ */
VERB_NOP = 0,
- /* Announcement of a node's existence:
+ /**
+ * Announcement of a node's existence:
* <[1] protocol version>
* <[1] software major version>
* <[1] software minor version>
@@ -542,6 +540,8 @@ public:
* <[...] binary serialized identity (see Identity)>
* <[1] destination address type>
* [<[...] destination address>]
+ * <[8] 64-bit world ID of current world>
+ * <[8] 64-bit timestamp of current world>
*
* This is the only message that ever must be sent in the clear, since it
* is used to push an identity to a new peer.
@@ -566,12 +566,15 @@ public:
* <[2] software revision (of responder)>
* <[1] destination address type (for this OK, not copied from HELLO)>
* [<[...] destination address>]
+ * <[2] 16-bit length of world update or 0 if none>
+ * [[...] world update]
*
* ERROR has no payload.
*/
VERB_HELLO = 1,
- /* Error response:
+ /**
+ * Error response:
* <[1] in-re verb>
* <[8] in-re packet ID>
* <[1] error code>
@@ -579,25 +582,31 @@ public:
*/
VERB_ERROR = 2,
- /* Success response:
+ /**
+ * Success response:
* <[1] in-re verb>
* <[8] in-re packet ID>
* <[...] request-specific payload>
*/
VERB_OK = 3,
- /* Query an identity by address:
+ /**
+ * Query an identity by address:
* <[5] address to look up>
*
* OK response payload:
* <[...] binary serialized identity>
*
- * ERROR response payload:
- * <[5] address>
+ * If querying a cluster, duplicate OK responses may occasionally occur.
+ * These should be discarded.
+ *
+ * If the address is not found, no response is generated. WHOIS requests
+ * will time out much like ARP requests and similar do in L2.
*/
VERB_WHOIS = 4,
- /* Meet another node at a given protocol address:
+ /**
+ * Meet another node at a given protocol address:
* <[1] flags (unused, currently 0)>
* <[5] ZeroTier address of peer that might be found at this address>
* <[2] 16-bit protocol address port>
@@ -616,11 +625,16 @@ public:
* may also ignore these messages if a peer is not known or is not being
* actively communicated with.
*
+ * Unfortunately the physical address format in this message pre-dates
+ * InetAddress's serialization format. :( ZeroTier is four years old and
+ * yes we've accumulated a tiny bit of cruft here and there.
+ *
* No OK or ERROR is generated.
*/
VERB_RENDEZVOUS = 5,
- /* ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME):
+ /**
+ * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME):
* <[8] 64-bit network ID>
* <[2] 16-bit ethertype>
* <[...] ethernet payload>
@@ -635,7 +649,8 @@ public:
*/
VERB_FRAME = 6,
- /* Full Ethernet frame with MAC addressing and optional fields:
+ /**
+ * Full Ethernet frame with MAC addressing and optional fields:
* <[8] 64-bit network ID>
* <[1] flags>
* [<[...] certificate of network membership>]
@@ -658,23 +673,44 @@ public:
*/
VERB_EXT_FRAME = 7,
- /* DEPRECATED */
- VERB_P5_MULTICAST_FRAME = 8,
+ /**
+ * ECHO request (a.k.a. ping):
+ * <[...] arbitrary payload to be echoed back>
+ *
+ * This generates OK with a copy of the transmitted payload. No ERROR
+ * is generated. Response to ECHO requests is optional.
+ *
+ * Support for fragmented echo packets is optional and their use is not
+ * recommended.
+ */
+ VERB_ECHO = 8,
- /* Announce interest in multicast group(s):
+ /**
+ * Announce interest in multicast group(s):
* <[8] 64-bit network ID>
* <[6] multicast Ethernet address>
* <[4] multicast additional distinguishing information (ADI)>
* [... additional tuples of network/address/adi ...]
*
- * LIKEs are sent to peers with whom you have a direct peer to peer
- * connection, and always including root servers.
+ * LIKEs may be sent to any peer, though a good implementation should
+ * restrict them to peers on the same network they're for and to network
+ * controllers and root servers. In the current network, root servers
+ * will provide the service of final multicast cache.
+ *
+ * It is recommended that NETWORK_MEMBERSHIP_CERTIFICATE pushes be sent
+ * along with MULTICAST_LIKE when pushing LIKEs to peers that do not
+ * share a network membership (such as root servers), since this can be
+ * used to authenticate GATHER requests and limit responses to peers
+ * authorized to talk on a network. (Should be an optional field here,
+ * but saving one or two packets every five minutes is not worth an
+ * ugly hack or protocol rev.)
*
* OK/ERROR are not generated.
*/
VERB_MULTICAST_LIKE = 9,
- /* Network member certificate replication/push:
+ /**
+ * Network member certificate replication/push:
* <[...] serialized certificate of membership>
* [ ... additional certificates may follow ...]
*
@@ -685,7 +721,8 @@ public:
*/
VERB_NETWORK_MEMBERSHIP_CERTIFICATE = 10,
- /* Network configuration request:
+ /**
+ * Network configuration request:
* <[8] 64-bit network ID>
* <[2] 16-bit length of request meta-data dictionary>
* <[...] string-serialized request meta-data>
@@ -720,7 +757,8 @@ public:
*/
VERB_NETWORK_CONFIG_REQUEST = 11,
- /* Network configuration refresh request:
+ /**
+ * Network configuration refresh request:
* <[...] array of 64-bit network IDs>
*
* This can be sent by the network controller to inform a node that it
@@ -731,7 +769,8 @@ public:
*/
VERB_NETWORK_CONFIG_REFRESH = 12,
- /* Request endpoints for multicast distribution:
+ /**
+ * Request endpoints for multicast distribution:
* <[8] 64-bit network ID>
* <[1] flags>
* <[6] MAC address of multicast group being queried>
@@ -747,6 +786,9 @@ public:
* to send multicast but does not have the desired number of recipient
* peers.
*
+ * More than one OK response can occur if the response is broken up across
+ * multiple packets or if querying a clustered node.
+ *
* OK response payload:
* <[8] 64-bit network ID>
* <[6] MAC address of multicast group being queried>
@@ -756,20 +798,12 @@ public:
* <[2] 16-bit number of members enumerated in this packet>
* <[...] series of 5-byte ZeroTier addresses of enumerated members>
*
- * If no endpoints are known, OK and ERROR are both optional. It's okay
- * to return nothing in that case since gathering is "lazy."
- *
- * ERROR response payload:
- * <[8] 64-bit network ID>
- * <[6] MAC address of multicast group being queried>
- * <[4] 32-bit ADI for multicast group being queried>
- *
- * ERRORs are optional and are only generated if permission is denied,
- * certificate of membership is out of date, etc.
+ * ERROR is not generated; queries that return no response are dropped.
*/
VERB_MULTICAST_GATHER = 13,
- /* Multicast frame:
+ /**
+ * Multicast frame:
* <[8] 64-bit network ID>
* <[1] flags>
* [<[...] network certificate of membership>]
@@ -810,7 +844,8 @@ public:
*/
VERB_MULTICAST_FRAME = 14,
- /* Ephemeral (PFS) key push: (UNFINISHED, NOT IMPLEMENTED YET)
+ /**
+ * Ephemeral (PFS) key push: (UNFINISHED, NOT IMPLEMENTED YET)
* <[2] flags (unused and reserved, must be 0)>
* <[2] length of padding / extra field section>
* <[...] padding / extra field section>
@@ -866,7 +901,8 @@ public:
*/
VERB_SET_EPHEMERAL_KEY = 15,
- /* Push of potential endpoints for direct communication:
+ /**
+ * Push of potential endpoints for direct communication:
* <[2] 16-bit number of paths>
* <[...] paths>
*
@@ -880,13 +916,10 @@ public:
*
* Path record flags:
* 0x01 - Forget this path if it is currently known
- * 0x02 - Blacklist this path, do not use
+ * 0x02 - (Unused)
* 0x04 - Disable encryption (trust: privacy)
* 0x08 - Disable encryption and authentication (trust: ultimate)
*
- * Address types and addresses are of the same format as the destination
- * address type and address in HELLO.
- *
* The receiver may, upon receiving a push, attempt to establish a
* direct link to one or more of the indicated addresses. It is the
* responsibility of the sender to limit which peers it pushes direct
@@ -906,7 +939,8 @@ public:
*/
VERB_PUSH_DIRECT_PATHS = 16,
- /* Source-routed circuit test message:
+ /**
+ * Source-routed circuit test message:
* <[5] address of originator of circuit test>
* <[2] 16-bit flags>
* <[8] 64-bit timestamp>
@@ -984,7 +1018,8 @@ public:
*/
VERB_CIRCUIT_TEST = 17,
- /* Circuit test hop report:
+ /**
+ * Circuit test hop report:
* <[8] 64-bit timestamp (from original test)>
* <[8] 64-bit test ID (from original test)>
* <[8] 64-bit reporter timestamp (reporter's clock, 0 if unspec)>
@@ -998,6 +1033,7 @@ public:
* <[2] 16-bit error code (set to 0, currently unused)>
* <[8] 64-bit report flags (set to 0, currently unused)>
* <[8] 64-bit source packet ID>
+ * <[5] upstream ZeroTier address from which test was received>
* <[1] 8-bit source packet hop count (ZeroTier hop count)>
* <[...] local wire address on which packet was received>
* <[...] remote wire address from which packet was received>
@@ -1017,7 +1053,50 @@ public:
* If a test report is received and no circuit test was sent, it should be
* ignored. This message generates no OK or ERROR response.
*/
- VERB_CIRCUIT_TEST_REPORT = 18
+ VERB_CIRCUIT_TEST_REPORT = 18,
+
+ /**
+ * Request proof of work:
+ * <[1] 8-bit proof of work type>
+ * <[1] 8-bit proof of work difficulty>
+ * <[2] 16-bit length of proof of work challenge>
+ * <[...] proof of work challenge>
+ *
+ * This requests that a peer perform a proof of work calucation. It can be
+ * sent by highly trusted peers (e.g. root servers, network controllers)
+ * under suspected denial of service conditions in an attempt to filter
+ * out "non-serious" peers and remain responsive to those proving their
+ * intent to actually communicate.
+ *
+ * If the peer obliges to perform the work, it does so and responds with
+ * an OK containing the result. Otherwise it may ignore the message or
+ * response with an ERROR_INVALID_REQUEST or ERROR_UNSUPPORTED_OPERATION.
+ *
+ * Proof of work type IDs:
+ * 0x01 - Salsa20/12+SHA512 hashcash function
+ *
+ * Salsa20/12+SHA512 is based on the following composite hash function:
+ *
+ * (1) Compute SHA512(candidate)
+ * (2) Use the first 256 bits of the result of #1 as a key to encrypt
+ * 131072 zero bytes with Salsa20/12 (with a zero IV).
+ * (3) Compute SHA512(the result of step #2)
+ * (4) Accept this candiate if the first [difficulty] bits of the result
+ * from step #3 are zero. Otherwise generate a new candidate and try
+ * again.
+ *
+ * This is performed repeatedly on candidates generated by appending the
+ * supplied challenge to an arbitrary nonce until a valid candidate
+ * is found. This chosen prepended nonce is then returned as the result
+ * in OK.
+ *
+ * OK payload:
+ * <[2] 16-bit length of result>
+ * <[...] computed proof of work>
+ *
+ * ERROR has no payload.
+ */
+ VERB_REQUEST_PROOF_OF_WORK = 19
};
/**
@@ -1034,7 +1113,7 @@ public:
/* Bad/unsupported protocol version */
ERROR_BAD_PROTOCOL_VERSION = 2,
- /* Unknown object queried (e.g. with WHOIS) */
+ /* Unknown object queried */
ERROR_OBJ_NOT_FOUND = 3,
/* HELLO pushed an identity whose address is already claimed */
diff --git a/node/Defaults.hpp b/node/Path.cpp
index c1df919b..e2475751 100644
--- a/node/Defaults.hpp
+++ b/node/Path.cpp
@@ -25,50 +25,21 @@
* LLC. Start here: http://www.zerotier.com/
*/
-#ifndef ZT_DEFAULTS_HPP
-#define ZT_DEFAULTS_HPP
-
-#include <stdexcept>
-#include <string>
-#include <vector>
-#include <map>
-
-#include "Constants.hpp"
-#include "Identity.hpp"
-#include "InetAddress.hpp"
+#include "Path.hpp"
+#include "AntiRecursion.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Node.hpp"
namespace ZeroTier {
-/**
- * Static configuration defaults
- *
- * These are the default values that ship baked into the ZeroTier binary. They
- * define the basic parameters required for it to connect to the rest of the
- * network and obtain software updates.
- */
-class Defaults
+bool Path::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
{
-public:
- Defaults();
-
- /**
- * Default root topology dictionary
- */
- const std::string defaultRootTopology;
-
- /**
- * Identities permitted to sign root topology dictionaries
- */
- const std::map< Address,Identity > rootTopologyAuthorities;
-
- /**
- * Address for IPv4 LAN auto-location broadcasts: 255.255.255.255:9993
- */
- const InetAddress v4Broadcast;
-};
-
-extern const Defaults ZT_DEFAULTS;
+ if (RR->node->putPacket(_localAddress,address(),data,len)) {
+ sent(now);
+ RR->antiRec->logOutgoingZT(data,len);
+ return true;
+ }
+ return false;
+}
} // namespace ZeroTier
-
-#endif
diff --git a/node/Path.hpp b/node/Path.hpp
index 6a69e071..00f8ed36 100644
--- a/node/Path.hpp
+++ b/node/Path.hpp
@@ -28,12 +28,29 @@
#ifndef ZT_PATH_HPP
#define ZT_PATH_HPP
+#include <stdint.h>
+#include <string.h>
+
+#include <stdexcept>
+#include <algorithm>
+
#include "Constants.hpp"
#include "InetAddress.hpp"
-#include "Utils.hpp"
+
+/**
+ * Flag indicating that this path is suboptimal
+ *
+ * This is used in cluster mode to indicate that the peer has been directed
+ * to a better path. This path can continue to be used but shouldn't be kept
+ * or advertised to other cluster members. Not used if clustering is not
+ * built and enabled.
+ */
+#define ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL 0x0001
namespace ZeroTier {
+class RuntimeEnvironment;
+
/**
* Base class for paths
*
@@ -42,43 +59,84 @@ namespace ZeroTier {
class Path
{
public:
+ Path() :
+ _lastSend(0),
+ _lastReceived(0),
+ _addr(),
+ _localAddress(),
+ _flags(0),
+ _ipScope(InetAddress::IP_SCOPE_NONE)
+ {
+ }
+
+ Path(const InetAddress &localAddress,const InetAddress &addr) :
+ _lastSend(0),
+ _lastReceived(0),
+ _addr(addr),
+ _localAddress(localAddress),
+ _flags(0),
+ _ipScope(addr.ipScope())
+ {
+ }
+
+ inline Path &operator=(const Path &p)
+ {
+ if (this != &p)
+ memcpy(this,&p,sizeof(Path));
+ return *this;
+ }
+
/**
- * Path trust category
+ * Called when a packet is sent to this remote path
*
- * Note that this is NOT peer trust and has nothing to do with root server
- * designations or other trust metrics. This indicates how much we trust
- * this path to be secure and/or private. A trust level of normal means
- * encrypt and authenticate all traffic. Privacy trust means we can send
- * traffic in the clear. Ultimate trust means we don't even need
- * authentication. Generally a private path would be a hard-wired local
- * LAN, while an ultimate trust path would be a physically isolated private
- * server backplane.
+ * This is called automatically by Path::send().
*
- * Nearly all paths will be normal trust. The other levels are for high
- * performance local SDN use only.
+ * @param t Time of send
+ */
+ inline void sent(uint64_t t) { _lastSend = t; }
+
+ /**
+ * Called when a packet is received from this remote path
*
- * These values MUST match ZT_LocalInterfaceAddressTrust in ZeroTierOne.h
+ * @param t Time of receive
*/
- enum Trust // NOTE: max 255
- {
- TRUST_NORMAL = 0,
- TRUST_PRIVACY = 10,
- TRUST_ULTIMATE = 20
- };
+ inline void received(uint64_t t) { _lastReceived = t; }
- Path() :
- _addr(),
- _ipScope(InetAddress::IP_SCOPE_NONE),
- _trust(TRUST_NORMAL)
+ /**
+ * @param now Current time
+ * @return True if this path appears active
+ */
+ inline bool active(uint64_t now) const
+ throw()
{
+ return ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT);
}
- Path(const InetAddress &addr,int metric,Trust trust) :
- _addr(addr),
- _ipScope(addr.ipScope()),
- _trust(trust)
- {
- }
+ /**
+ * Send a packet via this path
+ *
+ * @param RR Runtime environment
+ * @param data Packet data
+ * @param len Packet length
+ * @param now Current time
+ * @return True if transport reported success
+ */
+ bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now);
+
+ /**
+ * @return Address of local side of this path or NULL if unspecified
+ */
+ inline const InetAddress &localAddress() const throw() { return _localAddress; }
+
+ /**
+ * @return Time of last send to this path
+ */
+ inline uint64_t lastSend() const throw() { return _lastSend; }
+
+ /**
+ * @return Time of last receive from this path
+ */
+ inline uint64_t lastReceived() const throw() { return _lastReceived; }
/**
* @return Physical address
@@ -105,16 +163,13 @@ public:
}
/**
- * @return Path trust level
- */
- inline Trust trust() const throw() { return _trust; }
-
- /**
* @return True if path is considered reliable (no NAT keepalives etc. are needed)
*/
inline bool reliable() const throw()
{
- return ( (_addr.ss_family == AF_INET6) || ((_ipScope != InetAddress::IP_SCOPE_GLOBAL)&&(_ipScope != InetAddress::IP_SCOPE_PSEUDOPRIVATE)) );
+ if (_addr.ss_family == AF_INET)
+ return ((_ipScope != InetAddress::IP_SCOPE_GLOBAL)&&(_ipScope != InetAddress::IP_SCOPE_PSEUDOPRIVATE));
+ return true;
}
/**
@@ -155,10 +210,51 @@ public:
return false;
}
-protected:
+#ifdef ZT_ENABLE_CLUSTER
+ /**
+ * @param f New value of ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL
+ */
+ inline void setClusterSuboptimal(bool f) { _flags = ((f) ? (_flags | ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL) : (_flags & (~ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL))); }
+
+ /**
+ * @return True if ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL is set
+ */
+ inline bool isClusterSuboptimal() const { return ((_flags & ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL) != 0); }
+#endif
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b) const
+ {
+ b.append((uint8_t)0); // version
+ b.append((uint64_t)_lastSend);
+ b.append((uint64_t)_lastReceived);
+ _addr.serialize(b);
+ _localAddress.serialize(b);
+ b.append((uint16_t)_flags);
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ unsigned int p = startAt;
+ if (b[p++] != 0)
+ throw std::invalid_argument("invalid serialized Path");
+ _lastSend = b.template at<uint64_t>(p); p += 8;
+ _lastReceived = b.template at<uint64_t>(p); p += 8;
+ p += _addr.deserialize(b,p);
+ p += _localAddress.deserialize(b,p);
+ _flags = b.template at<uint16_t>(p); p += 2;
+ _ipScope = _addr.ipScope();
+ return (p - startAt);
+ }
+
+private:
+ uint64_t _lastSend;
+ uint64_t _lastReceived;
InetAddress _addr;
+ InetAddress _localAddress;
+ unsigned int _flags;
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
- Trust _trust;
};
} // namespace ZeroTier
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 757f822c..f0f43399 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -34,6 +34,8 @@
#include "Network.hpp"
#include "AntiRecursion.hpp"
#include "SelfAwareness.hpp"
+#include "Cluster.hpp"
+#include "Packet.hpp"
#include <algorithm>
@@ -52,14 +54,17 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
_lastMulticastFrame(0),
_lastAnnouncedTo(0),
_lastPathConfirmationSent(0),
- _lastDirectPathPush(0),
+ _lastDirectPathPushSent(0),
+ _lastDirectPathPushReceive(0),
_lastPathSort(0),
+ _vProto(0),
_vMajor(0),
_vMinor(0),
_vRevision(0),
_id(peerIdentity),
_numPaths(0),
_latency(0),
+ _directPathPushCutoffCount(0),
_networkComs(4),
_lastPushedComs(4)
{
@@ -77,81 +82,132 @@ void Peer::received(
uint64_t inRePacketId,
Packet::Verb inReVerb)
{
+#ifdef ZT_ENABLE_CLUSTER
+ bool suboptimalPath = false;
+ if ((RR->cluster)&&(hops == 0)) {
+ // Note: findBetterEndpoint() is first since we still want to check
+ // for a better endpoint even if we don't actually send a redirect.
+ InetAddress redirectTo;
+ if ( (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),remoteAddr,false)) && (verb != Packet::VERB_OK)&&(verb != Packet::VERB_ERROR)&&(verb != Packet::VERB_RENDEZVOUS)&&(verb != Packet::VERB_PUSH_DIRECT_PATHS) ) {
+ if (_vProto >= 5) {
+ // For newer peers we can send a more idiomatic verb: PUSH_DIRECT_PATHS.
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
+ outp.append((uint16_t)1); // count == 1
+ outp.append((uint8_t)0); // no flags
+ outp.append((uint16_t)0); // no extensions
+ if (redirectTo.ss_family == AF_INET) {
+ outp.append((uint8_t)4);
+ outp.append((uint8_t)6);
+ outp.append(redirectTo.rawIpData(),4);
+ } else {
+ outp.append((uint8_t)6);
+ outp.append((uint8_t)18);
+ outp.append(redirectTo.rawIpData(),16);
+ }
+ outp.append((uint16_t)redirectTo.port());
+ outp.armor(_key,true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
+ RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
+ } else {
+ // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere.
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS);
+ outp.append((uint8_t)0); // no flags
+ RR->identity.address().appendTo(outp);
+ outp.append((uint16_t)redirectTo.port());
+ if (redirectTo.ss_family == AF_INET) {
+ outp.append((uint8_t)4);
+ outp.append(redirectTo.rawIpData(),4);
+ } else {
+ outp.append((uint8_t)16);
+ outp.append(redirectTo.rawIpData(),16);
+ }
+ outp.armor(_key,true);
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
+ RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
+ }
+ suboptimalPath = true;
+ }
+ }
+#endif
+
const uint64_t now = RR->node->now();
bool needMulticastGroupAnnounce = false;
+ bool pathIsConfirmed = false;
- {
+ { // begin _lock
Mutex::Lock _l(_lock);
_lastReceive = now;
+ if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME))
+ _lastUnicastFrame = now;
+ else if (verb == Packet::VERB_MULTICAST_FRAME)
+ _lastMulticastFrame = now;
- if (!hops) {
- bool pathIsConfirmed = false;
+ if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) {
+ _lastAnnouncedTo = now;
+ needMulticastGroupAnnounce = true;
+ }
- /* Learn new paths from direct (hops == 0) packets */
- {
- unsigned int np = _numPaths;
- for(unsigned int p=0;p<np;++p) {
- if ((_paths[p].address() == remoteAddr)&&(_paths[p].localAddress() == localAddr)) {
- _paths[p].received(now);
- pathIsConfirmed = true;
- break;
- }
+ if (hops == 0) {
+ unsigned int np = _numPaths;
+ for(unsigned int p=0;p<np;++p) {
+ if ((_paths[p].address() == remoteAddr)&&(_paths[p].localAddress() == localAddr)) {
+ _paths[p].received(now);
+#ifdef ZT_ENABLE_CLUSTER
+ _paths[p].setClusterSuboptimal(suboptimalPath);
+#endif
+ pathIsConfirmed = true;
+ break;
}
+ }
+
+ if (!pathIsConfirmed) {
+ if (verb == Packet::VERB_OK) {
- if (!pathIsConfirmed) {
- if ((verb == Packet::VERB_OK)&&(inReVerb == Packet::VERB_HELLO)) {
-
- // Learn paths if they've been confirmed via a HELLO
- RemotePath *slot = (RemotePath *)0;
- if (np < ZT_MAX_PEER_NETWORK_PATHS) {
- // Add new path
- slot = &(_paths[np++]);
- } else {
- // Replace oldest non-fixed path
- uint64_t slotLRmin = 0xffffffffffffffffULL;
- for(unsigned int p=0;p<ZT_MAX_PEER_NETWORK_PATHS;++p) {
- if ((!_paths[p].fixed())&&(_paths[p].lastReceived() <= slotLRmin)) {
- slotLRmin = _paths[p].lastReceived();
- slot = &(_paths[p]);
- }
+ Path *slot = (Path *)0;
+ if (np < ZT_MAX_PEER_NETWORK_PATHS) {
+ slot = &(_paths[np++]);
+ } else {
+ uint64_t slotLRmin = 0xffffffffffffffffULL;
+ for(unsigned int p=0;p<ZT_MAX_PEER_NETWORK_PATHS;++p) {
+ if (_paths[p].lastReceived() <= slotLRmin) {
+ slotLRmin = _paths[p].lastReceived();
+ slot = &(_paths[p]);
}
}
- if (slot) {
- *slot = RemotePath(localAddr,remoteAddr,false);
- slot->received(now);
- _numPaths = np;
- pathIsConfirmed = true;
- _sortPaths(now);
- }
+ }
+ if (slot) {
+ *slot = Path(localAddr,remoteAddr);
+ slot->received(now);
+#ifdef ZT_ENABLE_CLUSTER
+ slot->setClusterSuboptimal(suboptimalPath);
+#endif
+ _numPaths = np;
+ pathIsConfirmed = true;
+ _sortPaths(now);
+ }
- } else {
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->broadcastHavePeer(_id);
+#endif
- /* If this path is not known, send a HELLO. We don't learn
- * paths without confirming that a bidirectional link is in
- * fact present, but any packet that decodes and authenticates
- * correctly is considered valid. */
- if ((now - _lastPathConfirmationSent) >= ZT_MIN_PATH_CONFIRMATION_INTERVAL) {
- _lastPathConfirmationSent = now;
- TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str());
- attemptToContactAt(RR,localAddr,remoteAddr,now);
- }
+ } else {
+ /* If this path is not known, send a HELLO. We don't learn
+ * paths without confirming that a bidirectional link is in
+ * fact present, but any packet that decodes and authenticates
+ * correctly is considered valid. */
+ if ((now - _lastPathConfirmationSent) >= ZT_MIN_PATH_CONFIRMATION_INTERVAL) {
+ _lastPathConfirmationSent = now;
+ TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str());
+ sendHELLO(RR,localAddr,remoteAddr,now);
}
+
}
}
}
-
- if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) {
- _lastAnnouncedTo = now;
- needMulticastGroupAnnounce = true;
- }
-
- if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME))
- _lastUnicastFrame = now;
- else if (verb == Packet::VERB_MULTICAST_FRAME)
- _lastMulticastFrame = now;
- }
+ } // end _lock
if (needMulticastGroupAnnounce) {
const std::vector< SharedPtr<Network> > networks(RR->node->allNetworks());
@@ -160,7 +216,7 @@ void Peer::received(
}
}
-void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now)
+void Peer::sendHELLO(const RuntimeEnvironment *RR,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int ttl)
{
// _lock not required here since _id is immutable and nothing else is accessed
@@ -170,69 +226,76 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
outp.append(now);
-
RR->identity.serialize(outp,false);
-
- switch(atAddress.ss_family) {
- case AF_INET:
- outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV4);
- outp.append(atAddress.rawIpData(),4);
- outp.append((uint16_t)atAddress.port());
- break;
- case AF_INET6:
- outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV6);
- outp.append(atAddress.rawIpData(),16);
- outp.append((uint16_t)atAddress.port());
- break;
- default:
- outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_NONE);
- break;
- }
+ atAddress.serialize(outp);
+ outp.append((uint64_t)RR->topology->worldId());
+ outp.append((uint64_t)RR->topology->worldTimestamp());
outp.armor(_key,false); // HELLO is sent in the clear
- RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
+ RR->antiRec->logOutgoingZT(outp.data(),outp.size());
+ RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size(),ttl);
}
-void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
+bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily)
{
+ Path *p = (Path *)0;
+
Mutex::Lock _l(_lock);
- RemotePath *const bestPath = _getBestPath(now);
- if (bestPath) {
- if ((now - bestPath->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) {
- TRACE("PING %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str());
- attemptToContactAt(RR,bestPath->localAddress(),bestPath->address(),now);
- bestPath->sent(now);
- } else if (((now - bestPath->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!bestPath->reliable())) {
+ if (inetAddressFamily != 0) {
+ p = _getBestPath(now,inetAddressFamily);
+ } else {
+ p = _getBestPath(now);
+ }
+
+ if (p) {
+ if ((now - p->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) {
+ //TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived());
+ sendHELLO(RR,p->localAddress(),p->address(),now);
+ p->sent(now);
+ } else if (((now - p->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!p->reliable())) {
+ //TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived());
_natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads
- TRACE("NAT keepalive %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str());
- RR->node->putPacket(bestPath->localAddress(),bestPath->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf));
- bestPath->sent(now);
+ RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf));
+ p->sent(now);
+ } else {
+ //TRACE("no PING or NAT keepalive: addr==%s reliable==%d %llums/%llums send/receive inactivity",p->address().toString().c_str(),(int)p->reliable(),now - p->lastSend(),now - p->lastReceived());
}
+ return true;
}
+
+ return false;
}
-void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force)
+void Peer::pushDirectPaths(const RuntimeEnvironment *RR,Path *path,uint64_t now,bool force)
{
+#ifdef ZT_ENABLE_CLUSTER
+ // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection
+ if (RR->cluster)
+ return;
+#endif
+
Mutex::Lock _l(_lock);
- if (((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) {
- _lastDirectPathPush = now;
+ if (((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) {
+ _lastDirectPathPushSent = now;
- std::vector<Path> dps(RR->node->directPaths());
+ std::vector<InetAddress> dps(RR->node->directPaths());
+ if (dps.empty())
+ return;
#ifdef ZT_TRACE
{
std::string ps;
- for(std::vector<Path>::const_iterator p(dps.begin());p!=dps.end();++p) {
+ for(std::vector<InetAddress>::const_iterator p(dps.begin());p!=dps.end();++p) {
if (ps.length() > 0)
ps.push_back(',');
- ps.append(p->address().toString());
+ ps.append(p->toString());
}
TRACE("pushing %u direct paths to %s: %s",(unsigned int)dps.size(),_id.address().toString().c_str(),ps.c_str());
}
#endif
- std::vector<Path>::const_iterator p(dps.begin());
+ std::vector<InetAddress>::const_iterator p(dps.begin());
while (p != dps.end()) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
outp.addSize(2); // leave room for count
@@ -240,7 +303,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_
unsigned int count = 0;
while ((p != dps.end())&&((outp.size() + 24) < ZT_PROTO_MAX_PACKET_LENGTH)) {
uint8_t addressType = 4;
- switch(p->address().ss_family) {
+ switch(p->ss_family) {
case AF_INET:
break;
case AF_INET6:
@@ -252,6 +315,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_
}
uint8_t flags = 0;
+ /* TODO: path trust is not implemented yet
switch(p->trust()) {
default:
break;
@@ -262,13 +326,14 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_
flags |= (0x04 | 0x08); // no encryption, no authentication (redundant but go ahead and set both)
break;
}
+ */
outp.append(flags);
outp.append((uint16_t)0); // no extensions
outp.append(addressType);
outp.append((uint8_t)((addressType == 4) ? 6 : 18));
- outp.append(p->address().rawIpData(),((addressType == 4) ? 4 : 16));
- outp.append((uint16_t)p->address().port());
+ outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16));
+ outp.append((uint16_t)p->port());
++count;
++p;
@@ -283,59 +348,6 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_
}
}
-void Peer::addPath(const RemotePath &newp,uint64_t now)
-{
- Mutex::Lock _l(_lock);
-
- unsigned int np = _numPaths;
-
- for(unsigned int p=0;p<np;++p) {
- if (_paths[p].address() == newp.address()) {
- _paths[p].setFixed(newp.fixed());
- _sortPaths(now);
- return;
- }
- }
-
- RemotePath *slot = (RemotePath *)0;
- if (np < ZT_MAX_PEER_NETWORK_PATHS) {
- // Add new path
- slot = &(_paths[np++]);
- } else {
- // Replace oldest non-fixed path
- uint64_t slotLRmin = 0xffffffffffffffffULL;
- for(unsigned int p=0;p<ZT_MAX_PEER_NETWORK_PATHS;++p) {
- if ((!_paths[p].fixed())&&(_paths[p].lastReceived() <= slotLRmin)) {
- slotLRmin = _paths[p].lastReceived();
- slot = &(_paths[p]);
- }
- }
- }
- if (slot) {
- *slot = newp;
- _numPaths = np;
- }
-
- _sortPaths(now);
-}
-
-void Peer::clearPaths(bool fixedToo)
-{
- if (fixedToo) {
- _numPaths = 0;
- } else {
- unsigned int np = _numPaths;
- unsigned int x = 0;
- unsigned int y = 0;
- while (x < np) {
- if (_paths[x].fixed())
- _paths[y++] = _paths[x];
- ++x;
- }
- _numPaths = y;
- }
-}
-
bool Peer::resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope scope,uint64_t now)
{
Mutex::Lock _l(_lock);
@@ -344,12 +356,9 @@ bool Peer::resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope sc
unsigned int y = 0;
while (x < np) {
if (_paths[x].address().ipScope() == scope) {
- if (_paths[x].fixed()) {
- attemptToContactAt(RR,_paths[x].localAddress(),_paths[x].address(),now);
- _paths[y++] = _paths[x]; // keep fixed paths
- }
+ sendHELLO(RR,_paths[x].localAddress(),_paths[x].address(),now);
} else {
- _paths[y++] = _paths[x]; // keep paths not in this scope
+ _paths[y++] = _paths[x];
}
++x;
}
@@ -497,7 +506,7 @@ struct _SortPathsByQuality
{
uint64_t _now;
_SortPathsByQuality(const uint64_t now) : _now(now) {}
- inline bool operator()(const RemotePath &a,const RemotePath &b) const
+ inline bool operator()(const Path &a,const Path &b) const
{
const uint64_t qa = (
((uint64_t)a.active(_now) << 63) |
@@ -517,7 +526,7 @@ void Peer::_sortPaths(const uint64_t now)
std::sort(&(_paths[0]),&(_paths[_numPaths]),_SortPathsByQuality(now));
}
-RemotePath *Peer::_getBestPath(const uint64_t now)
+Path *Peer::_getBestPath(const uint64_t now)
{
// assumes _lock is locked
if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL)
@@ -529,7 +538,22 @@ RemotePath *Peer::_getBestPath(const uint64_t now)
if (_paths[0].active(now))
return &(_paths[0]);
}
- return (RemotePath *)0;
+ return (Path *)0;
+}
+
+Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily)
+{
+ // assumes _lock is locked
+ if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL)
+ _sortPaths(now);
+ for(int k=0;k<2;++k) { // try once, and if it fails sort and try one more time
+ for(unsigned int i=0;i<_numPaths;++i) {
+ if ((_paths[i].active(now))&&((int)_paths[i].address().ss_family == inetAddressFamily))
+ return &(_paths[i]);
+ }
+ _sortPaths(now);
+ }
+ return (Path *)0;
}
} // namespace ZeroTier
diff --git a/node/Peer.hpp b/node/Peer.hpp
index 0988561a..7b8d18ea 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -41,7 +41,7 @@
#include "RuntimeEnvironment.hpp"
#include "CertificateOfMembership.hpp"
-#include "RemotePath.hpp"
+#include "Path.hpp"
#include "Address.hpp"
#include "Utils.hpp"
#include "Identity.hpp"
@@ -130,12 +130,12 @@ public:
Packet::Verb inReVerb = Packet::VERB_NOP);
/**
- * Get the best direct path to this peer
+ * Get the current best direct path to this peer
*
* @param now Current time
- * @return Best path or NULL if there are no active (or fixed) direct paths
+ * @return Best path or NULL if there are no active direct paths
*/
- inline RemotePath *getBestPath(uint64_t now)
+ inline Path *getBestPath(uint64_t now)
{
Mutex::Lock _l(_lock);
return _getBestPath(now);
@@ -150,14 +150,14 @@ public:
* @param now Current time
* @return Path used on success or NULL on failure
*/
- inline RemotePath *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
+ inline Path *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
{
- RemotePath *bestPath = getBestPath(now);
+ Path *bestPath = getBestPath(now);
if (bestPath) {
if (bestPath->send(RR,data,len,now))
return bestPath;
}
- return (RemotePath *)0;
+ return (Path *)0;
}
/**
@@ -170,16 +170,19 @@ public:
* @param localAddr Local address
* @param atAddress Destination address
* @param now Current time
+ * @param ttl Desired IP TTL (default: 0 to leave alone)
*/
- void attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now);
+ void sendHELLO(const RuntimeEnvironment *RR,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int ttl = 0);
/**
* Send pings or keepalives depending on configured timeouts
*
* @param RR Runtime environment
* @param now Current time
+ * @param inetAddressFamily Keep this address family alive, or 0 to simply pick current best ignoring family
+ * @return True if at least one direct path seems alive
*/
- void doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
+ bool doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily);
/**
* Push direct paths if we haven't done so in [rate limit] milliseconds
@@ -189,14 +192,14 @@ public:
* @param now Current time
* @param force If true, push regardless of rate limit
*/
- void pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force);
+ void pushDirectPaths(const RuntimeEnvironment *RR,Path *path,uint64_t now,bool force);
/**
* @return All known direct paths to this peer
*/
- inline std::vector<RemotePath> paths() const
+ inline std::vector<Path> paths() const
{
- std::vector<RemotePath> pp;
+ std::vector<Path> pp;
Mutex::Lock _l(_lock);
for(unsigned int p=0,np=_numPaths;p<np;++p)
pp.push_back(_paths[p]);
@@ -204,32 +207,6 @@ public:
}
/**
- * @return Time of last direct packet receive for any path
- */
- inline uint64_t lastDirectReceive() const
- throw()
- {
- Mutex::Lock _l(_lock);
- uint64_t x = 0;
- for(unsigned int p=0,np=_numPaths;p<np;++p)
- x = std::max(x,_paths[p].lastReceived());
- return x;
- }
-
- /**
- * @return Time of last direct packet send for any path
- */
- inline uint64_t lastDirectSend() const
- throw()
- {
- Mutex::Lock _l(_lock);
- uint64_t x = 0;
- for(unsigned int p=0,np=_numPaths;p<np;++p)
- x = std::max(x,_paths[p].lastSend());
- return x;
- }
-
- /**
* @return Time of last receive of anything, whether direct or relayed
*/
inline uint64_t lastReceive() const throw() { return _lastReceive; }
@@ -255,27 +232,44 @@ public:
inline uint64_t lastAnnouncedTo() const throw() { return _lastAnnouncedTo; }
/**
- * @return True if peer has received an actual data frame within ZT_PEER_ACTIVITY_TIMEOUT milliseconds
+ * @return True if this peer is actively sending real network frames
+ */
+ inline uint64_t activelyTransferringFrames(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); }
+
+ /**
+ * @return Latency in milliseconds or 0 if unknown
*/
- inline uint64_t alive(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); }
+ inline unsigned int latency() const { return _latency; }
/**
- * @return Current latency or 0 if unknown (max: 65535)
+ * This computes a quality score for relays and root servers
+ *
+ * If we haven't heard anything from these in ZT_PEER_ACTIVITY_TIMEOUT, they
+ * receive the worst possible quality (max unsigned int). Otherwise the
+ * quality is a product of latency and the number of potential missed
+ * pings. This causes roots and relays to switch over a bit faster if they
+ * fail.
+ *
+ * @return Relay quality score computed from latency and other factors, lower is better
*/
- inline unsigned int latency() const
- throw()
+ inline unsigned int relayQuality(const uint64_t now) const
{
+ const uint64_t tsr = now - _lastReceive;
+ if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT)
+ return (~(unsigned int)0);
unsigned int l = _latency;
- return std::min(l,(unsigned int)65535);
+ if (!l)
+ l = 0xffff;
+ return (l * (((unsigned int)tsr / (ZT_PEER_DIRECT_PING_DELAY + 1000)) + 1));
}
+
/**
* Update latency with a new direct measurment
*
* @param l Direct latency measurment in ms
*/
inline void addDirectLatencyMeasurment(unsigned int l)
- throw()
{
unsigned int ol = _latency;
if ((ol > 0)&&(ol < 10000))
@@ -284,16 +278,10 @@ public:
}
/**
- * @return True if this peer has at least one direct IP address path
- */
- inline bool hasDirectPath() const throw() { return (_numPaths != 0); }
-
- /**
* @param now Current time
- * @return True if this peer has at least one active or fixed direct path
+ * @return True if this peer has at least one active direct path
*/
inline bool hasActiveDirectPath(uint64_t now) const
- throw()
{
Mutex::Lock _l(_lock);
for(unsigned int p=0,np=_numPaths;p<np;++p) {
@@ -303,27 +291,25 @@ public:
return false;
}
+#ifdef ZT_ENABLE_CLUSTER
/**
- * Add a path (if we don't already have it)
- *
- * @param p New path to add
* @param now Current time
+ * @return True if this peer has at least one active direct path that is not cluster-suboptimal
*/
- void addPath(const RemotePath &newp,uint64_t now);
-
- /**
- * Clear paths
- *
- * @param fixedToo If true, clear fixed paths as well as learned ones
- */
- void clearPaths(bool fixedToo);
+ inline bool hasClusterOptimalPath(uint64_t now) const
+ {
+ Mutex::Lock _l(_lock);
+ for(unsigned int p=0,np=_numPaths;p<np;++p) {
+ if ((_paths[p].active(now))&&(!_paths[p].isClusterSuboptimal()))
+ return true;
+ }
+ return false;
+ }
+#endif
/**
* Reset paths within a given scope
*
- * For fixed paths in this scope, a packet is sent. Non-fixed paths in this
- * scope are forgotten.
- *
* @param RR Runtime environment
* @param scope IP scope of paths to reset
* @param now Current time
@@ -346,7 +332,6 @@ public:
*/
inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev)
{
- Mutex::Lock _l(_lock);
_vProto = (uint16_t)vproto;
_vMajor = (uint16_t)vmaj;
_vMinor = (uint16_t)vmin;
@@ -360,33 +345,6 @@ public:
inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
/**
- * Check whether this peer's version is both known and is at least what is specified
- *
- * @param major Major version to check against
- * @param minor Minor version
- * @param rev Revision
- * @return True if peer's version is at least supplied tuple
- */
- inline bool atLeastVersion(unsigned int major,unsigned int minor,unsigned int rev)
- throw()
- {
- Mutex::Lock _l(_lock);
- if ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)) {
- if (_vMajor > major)
- return true;
- else if (_vMajor == major) {
- if (_vMinor > minor)
- return true;
- else if (_vMinor == minor) {
- if (_vRevision >= rev)
- return true;
- }
- }
- }
- return false;
- }
-
- /**
* Get most recently active path addresses for IPv4 and/or IPv6
*
* Note that v4 and v6 are not modified if they are not found, so
@@ -430,6 +388,46 @@ public:
void clean(const RuntimeEnvironment *RR,uint64_t now);
/**
+ * Remove all paths with this remote address
+ *
+ * @param addr Remote address to remove
+ */
+ inline void removePathByAddress(const InetAddress &addr)
+ {
+ Mutex::Lock _l(_lock);
+ unsigned int np = _numPaths;
+ unsigned int x = 0;
+ unsigned int y = 0;
+ while (x < np) {
+ if (_paths[x].address() != addr)
+ _paths[y++] = _paths[x];
+ ++x;
+ }
+ _numPaths = y;
+ }
+
+ /**
+ * Update direct path push stats and return true if we should respond
+ *
+ * This is a circuit breaker to make VERB_PUSH_DIRECT_PATHS not particularly
+ * useful as a DDOS amplification attack vector. Otherwise a malicious peer
+ * could send loads of these and cause others to bombard arbitrary IPs with
+ * traffic.
+ *
+ * @param now Current time
+ * @return True if we should respond
+ */
+ inline bool shouldRespondToDirectPathPush(const uint64_t now)
+ {
+ Mutex::Lock _l(_lock);
+ if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME)
+ ++_directPathPushCutoffCount;
+ else _directPathPushCutoffCount = 0;
+ _lastDirectPathPushReceive = now;
+ return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT);
+ }
+
+ /**
* Find a common set of addresses by which two peers can link, if any
*
* @param a Peer A
@@ -454,10 +452,10 @@ public:
{
Mutex::Lock _l(_lock);
- const unsigned int atPos = b.size();
+ const unsigned int recSizePos = b.size();
b.addSize(4); // space for uint32_t field length
- b.append((uint32_t)1); // version of serialized Peer data
+ b.append((uint16_t)0); // version of serialized Peer data
_id.serialize(b,false);
@@ -467,15 +465,17 @@ public:
b.append((uint64_t)_lastMulticastFrame);
b.append((uint64_t)_lastAnnouncedTo);
b.append((uint64_t)_lastPathConfirmationSent);
- b.append((uint64_t)_lastDirectPathPush);
+ b.append((uint64_t)_lastDirectPathPushSent);
+ b.append((uint64_t)_lastDirectPathPushReceive);
b.append((uint64_t)_lastPathSort);
b.append((uint16_t)_vProto);
b.append((uint16_t)_vMajor);
b.append((uint16_t)_vMinor);
b.append((uint16_t)_vRevision);
b.append((uint32_t)_latency);
+ b.append((uint16_t)_directPathPushCutoffCount);
- b.append((uint32_t)_numPaths);
+ b.append((uint16_t)_numPaths);
for(unsigned int i=0;i<_numPaths;++i)
_paths[i].serialize(b);
@@ -502,7 +502,7 @@ public:
}
}
- b.setAt(atPos,(uint32_t)(b.size() - atPos)); // set size
+ b.template setAt<uint32_t>(recSizePos,(uint32_t)(b.size() - (recSizePos + 4))); // set size
}
/**
@@ -516,13 +516,12 @@ public:
template<unsigned int C>
static inline SharedPtr<Peer> deserializeNew(const Identity &myIdentity,const Buffer<C> &b,unsigned int &p)
{
- const uint32_t recSize = b.template at<uint32_t>(p);
+ const unsigned int recSize = b.template at<uint32_t>(p); p += 4;
if ((p + recSize) > b.size())
return SharedPtr<Peer>(); // size invalid
- p += 4;
- if (b.template at<uint32_t>(p) != 1)
+ if (b.template at<uint16_t>(p) != 0)
return SharedPtr<Peer>(); // version mismatch
- p += 4;
+ p += 2;
Identity npid;
p += npid.deserialize(b,p);
@@ -537,21 +536,23 @@ public:
np->_lastMulticastFrame = b.template at<uint64_t>(p); p += 8;
np->_lastAnnouncedTo = b.template at<uint64_t>(p); p += 8;
np->_lastPathConfirmationSent = b.template at<uint64_t>(p); p += 8;
- np->_lastDirectPathPush = b.template at<uint64_t>(p); p += 8;
+ np->_lastDirectPathPushSent = b.template at<uint64_t>(p); p += 8;
+ np->_lastDirectPathPushReceive = b.template at<uint64_t>(p); p += 8;
np->_lastPathSort = b.template at<uint64_t>(p); p += 8;
np->_vProto = b.template at<uint16_t>(p); p += 2;
np->_vMajor = b.template at<uint16_t>(p); p += 2;
np->_vMinor = b.template at<uint16_t>(p); p += 2;
np->_vRevision = b.template at<uint16_t>(p); p += 2;
np->_latency = b.template at<uint32_t>(p); p += 4;
+ np->_directPathPushCutoffCount = b.template at<uint16_t>(p); p += 2;
- const unsigned int numPaths = b.template at<uint32_t>(p); p += 4;
+ const unsigned int numPaths = b.template at<uint16_t>(p); p += 2;
for(unsigned int i=0;i<numPaths;++i) {
if (i < ZT_MAX_PEER_NETWORK_PATHS) {
p += np->_paths[np->_numPaths++].deserialize(b,p);
} else {
// Skip any paths beyond max, but still read stream
- RemotePath foo;
+ Path foo;
p += foo.deserialize(b,p);
}
}
@@ -575,25 +576,29 @@ public:
private:
void _sortPaths(const uint64_t now);
- RemotePath *_getBestPath(const uint64_t now);
+ Path *_getBestPath(const uint64_t now);
+ Path *_getBestPath(const uint64_t now,int inetAddressFamily);
+
+ unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized
- unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH];
uint64_t _lastUsed;
uint64_t _lastReceive; // direct or indirect
uint64_t _lastUnicastFrame;
uint64_t _lastMulticastFrame;
uint64_t _lastAnnouncedTo;
uint64_t _lastPathConfirmationSent;
- uint64_t _lastDirectPathPush;
+ uint64_t _lastDirectPathPushSent;
+ uint64_t _lastDirectPathPushReceive;
uint64_t _lastPathSort;
uint16_t _vProto;
uint16_t _vMajor;
uint16_t _vMinor;
uint16_t _vRevision;
Identity _id;
- RemotePath _paths[ZT_MAX_PEER_NETWORK_PATHS];
+ Path _paths[ZT_MAX_PEER_NETWORK_PATHS];
unsigned int _numPaths;
unsigned int _latency;
+ unsigned int _directPathPushCutoffCount;
struct _NetworkCom
{
diff --git a/node/Poly1305.cpp b/node/Poly1305.cpp
index 77b32a80..b78071f6 100644
--- a/node/Poly1305.cpp
+++ b/node/Poly1305.cpp
@@ -20,6 +20,9 @@ namespace ZeroTier {
#if 0
+// "Naive" implementation, which is slower... might still want this on some older
+// or weird platforms if the later versions have issues.
+
static inline void add(unsigned int h[17],const unsigned int c[17])
{
unsigned int j;
@@ -132,9 +135,236 @@ typedef struct poly1305_context {
unsigned char opaque[136];
} poly1305_context;
-/*
- poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition
-*/
+#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__))
+
+//////////////////////////////////////////////////////////////////////////////
+// 128-bit implementation for MSC and GCC from Poly1305-donna
+
+#if defined(_MSC_VER)
+ #include <intrin.h>
+
+ typedef struct uint128_t {
+ unsigned long long lo;
+ unsigned long long hi;
+ } uint128_t;
+
+ #define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi)
+ #define ADD(out, in) { unsigned long long t = out.lo; out.lo += in.lo; out.hi += (out.lo < t) + in.hi; }
+ #define ADDLO(out, in) { unsigned long long t = out.lo; out.lo += in; out.hi += (out.lo < t); }
+ #define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift)))
+ #define LO(in) (in.lo)
+
+// #define POLY1305_NOINLINE __declspec(noinline)
+#elif defined(__GNUC__)
+ #if defined(__SIZEOF_INT128__)
+ typedef unsigned __int128 uint128_t;
+ #else
+ typedef unsigned uint128_t __attribute__((mode(TI)));
+ #endif
+
+ #define MUL(out, x, y) out = ((uint128_t)x * y)
+ #define ADD(out, in) out += in
+ #define ADDLO(out, in) out += in
+ #define SHR(in, shift) (unsigned long long)(in >> (shift))
+ #define LO(in) (unsigned long long)(in)
+
+// #define POLY1305_NOINLINE __attribute__((noinline))
+#endif
+
+#define poly1305_block_size 16
+
+/* 17 + sizeof(size_t) + 8*sizeof(unsigned long long) */
+typedef struct poly1305_state_internal_t {
+ unsigned long long r[3];
+ unsigned long long h[3];
+ unsigned long long pad[2];
+ size_t leftover;
+ unsigned char buffer[poly1305_block_size];
+ unsigned char final;
+} poly1305_state_internal_t;
+
+/* interpret eight 8 bit unsigned integers as a 64 bit unsigned integer in little endian */
+static inline unsigned long long
+U8TO64(const unsigned char *p) {
+ return
+ (((unsigned long long)(p[0] & 0xff) ) |
+ ((unsigned long long)(p[1] & 0xff) << 8) |
+ ((unsigned long long)(p[2] & 0xff) << 16) |
+ ((unsigned long long)(p[3] & 0xff) << 24) |
+ ((unsigned long long)(p[4] & 0xff) << 32) |
+ ((unsigned long long)(p[5] & 0xff) << 40) |
+ ((unsigned long long)(p[6] & 0xff) << 48) |
+ ((unsigned long long)(p[7] & 0xff) << 56));
+}
+
+/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little endian */
+static inline void
+U64TO8(unsigned char *p, unsigned long long v) {
+ p[0] = (v ) & 0xff;
+ p[1] = (v >> 8) & 0xff;
+ p[2] = (v >> 16) & 0xff;
+ p[3] = (v >> 24) & 0xff;
+ p[4] = (v >> 32) & 0xff;
+ p[5] = (v >> 40) & 0xff;
+ p[6] = (v >> 48) & 0xff;
+ p[7] = (v >> 56) & 0xff;
+}
+
+static inline void
+poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ unsigned long long t0,t1;
+
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ t0 = U8TO64(&key[0]);
+ t1 = U8TO64(&key[8]);
+
+ st->r[0] = ( t0 ) & 0xffc0fffffff;
+ st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
+ st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f;
+
+ /* h = 0 */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+
+ /* save pad for later */
+ st->pad[0] = U8TO64(&key[16]);
+ st->pad[1] = U8TO64(&key[24]);
+
+ st->leftover = 0;
+ st->final = 0;
+}
+
+static inline void
+poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
+ const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
+ unsigned long long r0,r1,r2;
+ unsigned long long s1,s2;
+ unsigned long long h0,h1,h2;
+ unsigned long long c;
+ uint128_t d0,d1,d2,d;
+
+ r0 = st->r[0];
+ r1 = st->r[1];
+ r2 = st->r[2];
+
+ h0 = st->h[0];
+ h1 = st->h[1];
+ h2 = st->h[2];
+
+ s1 = r1 * (5 << 2);
+ s2 = r2 * (5 << 2);
+
+ while (bytes >= poly1305_block_size) {
+ unsigned long long t0,t1;
+
+ /* h += m[i] */
+ t0 = U8TO64(&m[0]);
+ t1 = U8TO64(&m[8]);
+
+ h0 += (( t0 ) & 0xfffffffffff);
+ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
+ h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit;
+
+ /* h *= r */
+ MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d);
+ MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d);
+ MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d);
+
+ /* (partial) h %= p */
+ c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff;
+ ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff;
+ ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff;
+ h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff;
+ h1 += c;
+
+ m += poly1305_block_size;
+ bytes -= poly1305_block_size;
+ }
+
+ st->h[0] = h0;
+ st->h[1] = h1;
+ st->h[2] = h2;
+}
+
+static inline void
+poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ unsigned long long h0,h1,h2,c;
+ unsigned long long g0,g1,g2;
+ unsigned long long t0,t1;
+
+ /* process the remaining block */
+ if (st->leftover) {
+ size_t i = st->leftover;
+ st->buffer[i] = 1;
+ for (i = i + 1; i < poly1305_block_size; i++)
+ st->buffer[i] = 0;
+ st->final = 1;
+ poly1305_blocks(st, st->buffer, poly1305_block_size);
+ }
+
+ /* fully carry h */
+ h0 = st->h[0];
+ h1 = st->h[1];
+ h2 = st->h[2];
+
+ c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
+ h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
+ h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += c;
+
+ /* compute h + -p */
+ g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff;
+ g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff;
+ g2 = h2 + c - ((unsigned long long)1 << 42);
+
+ /* select h if h < p, or h + -p if h >= p */
+ c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1;
+ g0 &= c;
+ g1 &= c;
+ g2 &= c;
+ c = ~c;
+ h0 = (h0 & c) | g0;
+ h1 = (h1 & c) | g1;
+ h2 = (h2 & c) | g2;
+
+ /* h = (h + pad) */
+ t0 = st->pad[0];
+ t1 = st->pad[1];
+
+ h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff;
+
+ /* mac = h % (2^128) */
+ h0 = ((h0 ) | (h1 << 44));
+ h1 = ((h1 >> 20) | (h2 << 24));
+
+ U64TO8(&mac[0], h0);
+ U64TO8(&mac[8], h1);
+
+ /* zero out the state */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+ st->r[0] = 0;
+ st->r[1] = 0;
+ st->r[2] = 0;
+ st->pad[0] = 0;
+ st->pad[1] = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#else
+
+//////////////////////////////////////////////////////////////////////////////
+// More portable 64-bit implementation
#define poly1305_block_size 16
@@ -257,43 +487,6 @@ poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t by
}
static inline void
-poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
- poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
- size_t i;
-
- /* handle leftover */
- if (st->leftover) {
- size_t want = (poly1305_block_size - st->leftover);
- if (want > bytes)
- want = bytes;
- for (i = 0; i < want; i++)
- st->buffer[st->leftover + i] = m[i];
- bytes -= want;
- m += want;
- st->leftover += want;
- if (st->leftover < poly1305_block_size)
- return;
- poly1305_blocks(st, st->buffer, poly1305_block_size);
- st->leftover = 0;
- }
-
- /* process full blocks */
- if (bytes >= poly1305_block_size) {
- size_t want = (bytes & ~(poly1305_block_size - 1));
- poly1305_blocks(st, m, want);
- m += want;
- bytes -= want;
- }
-
- /* store leftover */
- if (bytes) {
- for (i = 0; i < bytes; i++)
- st->buffer[st->leftover + i] = m[i];
- st->leftover += bytes;
- }
-}
-
-static inline void
poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned long h0,h1,h2,h3,h4,c;
@@ -380,6 +573,47 @@ poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
st->pad[3] = 0;
}
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // MSC/GCC or not
+
+static inline void
+poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ size_t i;
+
+ /* handle leftover */
+ if (st->leftover) {
+ size_t want = (poly1305_block_size - st->leftover);
+ if (want > bytes)
+ want = bytes;
+ for (i = 0; i < want; i++)
+ st->buffer[st->leftover + i] = m[i];
+ bytes -= want;
+ m += want;
+ st->leftover += want;
+ if (st->leftover < poly1305_block_size)
+ return;
+ poly1305_blocks(st, st->buffer, poly1305_block_size);
+ st->leftover = 0;
+ }
+
+ /* process full blocks */
+ if (bytes >= poly1305_block_size) {
+ size_t want = (bytes & ~(poly1305_block_size - 1));
+ poly1305_blocks(st, m, want);
+ m += want;
+ bytes -= want;
+ }
+
+ /* store leftover */
+ if (bytes) {
+ for (i = 0; i < bytes; i++)
+ st->buffer[st->leftover + i] = m[i];
+ st->leftover += bytes;
+ }
+}
+
} // anonymous namespace
void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key)
diff --git a/node/RemotePath.hpp b/node/RemotePath.hpp
deleted file mode 100644
index d2f99997..00000000
--- a/node/RemotePath.hpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_REMOTEPATH_HPP
-#define ZT_REMOTEPATH_HPP
-
-#include <stdint.h>
-#include <string.h>
-
-#include <stdexcept>
-#include <algorithm>
-
-#include "Path.hpp"
-#include "Node.hpp"
-#include "AntiRecursion.hpp"
-#include "RuntimeEnvironment.hpp"
-
-#define ZT_REMOTEPATH_FLAG_FIXED 0x0001
-
-namespace ZeroTier {
-
-/**
- * Path to a remote peer
- *
- * This extends Path to include status information about path activity.
- */
-class RemotePath : public Path
-{
-public:
- RemotePath() :
- Path(),
- _lastSend(0),
- _lastReceived(0),
- _localAddress(),
- _flags(0) {}
-
- RemotePath(const InetAddress &localAddress,const InetAddress &addr,bool fixed) :
- Path(addr,0,TRUST_NORMAL),
- _lastSend(0),
- _lastReceived(0),
- _localAddress(localAddress),
- _flags(fixed ? ZT_REMOTEPATH_FLAG_FIXED : 0) {}
-
- inline const InetAddress &localAddress() const throw() { return _localAddress; }
-
- inline uint64_t lastSend() const throw() { return _lastSend; }
- inline uint64_t lastReceived() const throw() { return _lastReceived; }
-
- /**
- * @return Is this a fixed path?
- */
- inline bool fixed() const throw() { return ((_flags & ZT_REMOTEPATH_FLAG_FIXED) != 0); }
-
- /**
- * @param f New value of fixed flag
- */
- inline void setFixed(const bool f)
- throw()
- {
- if (f)
- _flags |= ZT_REMOTEPATH_FLAG_FIXED;
- else _flags &= ~ZT_REMOTEPATH_FLAG_FIXED;
- }
-
- /**
- * Called when a packet is sent to this remote path
- *
- * This is called automatically by RemotePath::send().
- *
- * @param t Time of send
- */
- inline void sent(uint64_t t)
- throw()
- {
- _lastSend = t;
- }
-
- /**
- * Called when a packet is received from this remote path
- *
- * @param t Time of receive
- */
- inline void received(uint64_t t)
- throw()
- {
- _lastReceived = t;
- }
-
- /**
- * @param now Current time
- * @return True if this path is fixed or has received data in last ACTIVITY_TIMEOUT ms
- */
- inline bool active(uint64_t now) const
- throw()
- {
- return ( ((_flags & ZT_REMOTEPATH_FLAG_FIXED) != 0) || ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT) );
- }
-
- /**
- * Send a packet via this path
- *
- * @param RR Runtime environment
- * @param data Packet data
- * @param len Packet length
- * @param now Current time
- * @return True if transport reported success
- */
- inline bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
- {
- if (RR->node->putPacket(_localAddress,address(),data,len)) {
- sent(now);
- RR->antiRec->logOutgoingZT(data,len);
- return true;
- }
- return false;
- }
-
- template<unsigned int C>
- inline void serialize(Buffer<C> &b) const
- {
- b.append((uint8_t)1); // version
- _addr.serialize(b);
- b.append((uint8_t)_trust);
- b.append((uint64_t)_lastSend);
- b.append((uint64_t)_lastReceived);
- _localAddress.serialize(b);
- b.append((uint16_t)_flags);
- }
-
- template<unsigned int C>
- inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
- {
- unsigned int p = startAt;
- if (b[p++] != 1)
- throw std::invalid_argument("invalid serialized RemotePath");
- p += _addr.deserialize(b,p);
- _ipScope = _addr.ipScope();
- _trust = (Path::Trust)b[p++];
- _lastSend = b.template at<uint64_t>(p); p += 8;
- _lastReceived = b.template at<uint64_t>(p); p += 8;
- p += _localAddress.deserialize(b,p);
- _flags = b.template at<uint16_t>(p); p += 2;
- return (p - startAt);
- }
-
-protected:
- uint64_t _lastSend;
- uint64_t _lastReceived;
- InetAddress _localAddress;
- uint16_t _flags;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp
index e5d1f446..10cc6ec0 100644
--- a/node/RuntimeEnvironment.hpp
+++ b/node/RuntimeEnvironment.hpp
@@ -32,6 +32,7 @@
#include "Constants.hpp"
#include "Identity.hpp"
+#include "Mutex.hpp"
namespace ZeroTier {
@@ -43,6 +44,8 @@ class Multicaster;
class AntiRecursion;
class NetworkController;
class SelfAwareness;
+class Cluster;
+class DeferredPackets;
/**
* Holds global state for an instance of ZeroTier::Node
@@ -51,14 +54,18 @@ class RuntimeEnvironment
{
public:
RuntimeEnvironment(Node *n) :
- node(n),
- identity(),
- localNetworkController((NetworkController *)0),
- sw((Switch *)0),
- mc((Multicaster *)0),
- antiRec((AntiRecursion *)0),
- topology((Topology *)0),
- sa((SelfAwareness *)0)
+ node(n)
+ ,identity()
+ ,localNetworkController((NetworkController *)0)
+ ,sw((Switch *)0)
+ ,mc((Multicaster *)0)
+ ,antiRec((AntiRecursion *)0)
+ ,topology((Topology *)0)
+ ,sa((SelfAwareness *)0)
+ ,dp((DeferredPackets *)0)
+#ifdef ZT_ENABLE_CLUSTER
+ ,cluster((Cluster *)0)
+#endif
{
}
@@ -86,6 +93,15 @@ public:
AntiRecursion *antiRec;
Topology *topology;
SelfAwareness *sa;
+ DeferredPackets *dp;
+
+#ifdef ZT_ENABLE_CLUSTER
+ Cluster *cluster;
+#endif
+
+ // This is set to >0 if background threads are waiting on deferred
+ // packets, otherwise 'dp' should not be used.
+ volatile int dpEnabled;
};
} // namespace ZeroTier
diff --git a/node/Salsa20.cpp b/node/Salsa20.cpp
index f8cf8591..3aa19ac6 100644
--- a/node/Salsa20.cpp
+++ b/node/Salsa20.cpp
@@ -66,7 +66,7 @@ static const _s20sseconsts _S20SSECONSTANTS;
namespace ZeroTier {
-void Salsa20::init(const void *key,unsigned int kbits,const void *iv,unsigned int rounds)
+void Salsa20::init(const void *key,unsigned int kbits,const void *iv)
throw()
{
#ifdef ZT_SALSA20_SSE
@@ -121,11 +121,9 @@ void Salsa20::init(const void *key,unsigned int kbits,const void *iv,unsigned in
_state.i[15] = U8TO32_LITTLE(constants + 12);
_state.i[0] = U8TO32_LITTLE(constants + 0);
#endif
-
- _roundsDiv4 = rounds / 4;
}
-void Salsa20::encrypt(const void *in,void *out,unsigned int bytes)
+void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes)
throw()
{
uint8_t tmp[64];
@@ -175,104 +173,169 @@ void Salsa20::encrypt(const void *in,void *out,unsigned int bytes)
__m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1]));
__m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2]));
__m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3]));
+ __m128i T;
__m128i X0s = X0;
__m128i X1s = X1;
__m128i X2s = X2;
__m128i X3s = X3;
- for (i=0;i<_roundsDiv4;++i) {
- __m128i T = _mm_add_epi32(X0, X3);
- X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7));
- X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25));
- T = _mm_add_epi32(X1, X0);
- X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
- X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
- T = _mm_add_epi32(X2, X1);
- X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13));
- X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19));
- T = _mm_add_epi32(X3, X2);
- X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
- X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));
-
- X1 = _mm_shuffle_epi32(X1, 0x93);
- X2 = _mm_shuffle_epi32(X2, 0x4E);
- X3 = _mm_shuffle_epi32(X3, 0x39);
-
- T = _mm_add_epi32(X0, X1);
- X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7));
- X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25));
- T = _mm_add_epi32(X3, X0);
- X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
- X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
- T = _mm_add_epi32(X2, X3);
- X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13));
- X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19));
- T = _mm_add_epi32(X1, X2);
- X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
- X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));
-
- X1 = _mm_shuffle_epi32(X1, 0x39);
- X2 = _mm_shuffle_epi32(X2, 0x4E);
- X3 = _mm_shuffle_epi32(X3, 0x93);
-
- // --
-
- T = _mm_add_epi32(X0, X3);
- X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7));
- X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25));
- T = _mm_add_epi32(X1, X0);
- X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
- X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
- T = _mm_add_epi32(X2, X1);
- X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13));
- X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19));
- T = _mm_add_epi32(X3, X2);
- X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
- X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));
-
- X1 = _mm_shuffle_epi32(X1, 0x93);
- X2 = _mm_shuffle_epi32(X2, 0x4E);
- X3 = _mm_shuffle_epi32(X3, 0x39);
-
- T = _mm_add_epi32(X0, X1);
- X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7));
- X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25));
- T = _mm_add_epi32(X3, X0);
- X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
- X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
- T = _mm_add_epi32(X2, X3);
- X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13));
- X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19));
- T = _mm_add_epi32(X1, X2);
- X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
- X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));
-
- X1 = _mm_shuffle_epi32(X1, 0x39);
- X2 = _mm_shuffle_epi32(X2, 0x4E);
- X3 = _mm_shuffle_epi32(X3, 0x93);
- }
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
X0 = _mm_add_epi32(X0s,X0);
X1 = _mm_add_epi32(X1s,X1);
X2 = _mm_add_epi32(X2s,X2);
X3 = _mm_add_epi32(X3s,X3);
- {
- __m128i k02 = _mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32));
- k02 = _mm_shuffle_epi32(k02, _MM_SHUFFLE(0, 1, 2, 3));
- __m128i k13 = _mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32));
- k13 = _mm_shuffle_epi32(k13, _MM_SHUFFLE(0, 1, 2, 3));
- __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32));
- __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32));
-
- const float *const mv = (const float *)m;
- float *const cv = (float *)c;
-
- _mm_storeu_ps(cv,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(mv)))));
- _mm_storeu_ps(cv + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(mv + 4)))));
- _mm_storeu_ps(cv + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(mv + 8)))));
- _mm_storeu_ps(cv + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(mv + 12)))));
- }
+ __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3));
+ __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3));
+ __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32));
+ __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32));
+ _mm_storeu_ps(reinterpret_cast<float *>(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m))))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 4)))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 8)))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 12)))));
if (!(++_state.i[8])) {
++_state.i[5]; // state reordered for SSE
@@ -296,76 +359,942 @@ void Salsa20::encrypt(const void *in,void *out,unsigned int bytes)
x14 = j14;
x15 = j15;
- for(i=0;i<_roundsDiv4;++i) {
- x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
- x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
- x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
- x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
- x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
- x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
- x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
- x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
- x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
- x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
- x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
- x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
- x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
- x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
- x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
- x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
- x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
- x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
- x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
- x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
- x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
- x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
- x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
- x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
- x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
- x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
- x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
- x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
- x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
- x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
- x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
- x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
-
- // --
-
- x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
- x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
- x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
- x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
- x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
- x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
- x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
- x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
- x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
- x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
- x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
- x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
- x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
- x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
- x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
- x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
- x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
- x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
- x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
- x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
- x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
- x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
- x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
- x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
- x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
- x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
- x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
- x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
- x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
- x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
- x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
- x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ x0 = PLUS(x0,j0);
+ x1 = PLUS(x1,j1);
+ x2 = PLUS(x2,j2);
+ x3 = PLUS(x3,j3);
+ x4 = PLUS(x4,j4);
+ x5 = PLUS(x5,j5);
+ x6 = PLUS(x6,j6);
+ x7 = PLUS(x7,j7);
+ x8 = PLUS(x8,j8);
+ x9 = PLUS(x9,j9);
+ x10 = PLUS(x10,j10);
+ x11 = PLUS(x11,j11);
+ x12 = PLUS(x12,j12);
+ x13 = PLUS(x13,j13);
+ x14 = PLUS(x14,j14);
+ x15 = PLUS(x15,j15);
+
+ U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0)));
+ U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4)));
+ U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8)));
+ U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12)));
+ U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16)));
+ U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20)));
+ U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24)));
+ U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28)));
+ U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32)));
+ U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36)));
+ U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40)));
+ U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44)));
+ U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48)));
+ U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52)));
+ U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56)));
+ U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60)));
+
+ if (!(++j8)) {
+ ++j9;
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+#endif
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i)
+ ctarget[i] = c[i];
+ }
+
+#ifndef ZT_SALSA20_SSE
+ _state.i[8] = j8;
+ _state.i[9] = j9;
+#endif
+
+ return;
+ }
+
+ bytes -= 64;
+ c += 64;
+ m += 64;
+ }
+}
+
+void Salsa20::encrypt20(const void *in,void *out,unsigned int bytes)
+ throw()
+{
+ uint8_t tmp[64];
+ const uint8_t *m = (const uint8_t *)in;
+ uint8_t *c = (uint8_t *)out;
+ uint8_t *ctarget = c;
+ unsigned int i;
+
+#ifndef ZT_SALSA20_SSE
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+#endif
+
+ if (!bytes)
+ return;
+
+#ifndef ZT_SALSA20_SSE
+ j0 = _state.i[0];
+ j1 = _state.i[1];
+ j2 = _state.i[2];
+ j3 = _state.i[3];
+ j4 = _state.i[4];
+ j5 = _state.i[5];
+ j6 = _state.i[6];
+ j7 = _state.i[7];
+ j8 = _state.i[8];
+ j9 = _state.i[9];
+ j10 = _state.i[10];
+ j11 = _state.i[11];
+ j12 = _state.i[12];
+ j13 = _state.i[13];
+ j14 = _state.i[14];
+ j15 = _state.i[15];
+#endif
+
+ for (;;) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i)
+ tmp[i] = m[i];
+ m = tmp;
+ ctarget = c;
+ c = tmp;
}
+#ifdef ZT_SALSA20_SSE
+ __m128i X0 = _mm_loadu_si128((const __m128i *)&(_state.v[0]));
+ __m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1]));
+ __m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2]));
+ __m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3]));
+ __m128i T;
+ __m128i X0s = X0;
+ __m128i X1s = X1;
+ __m128i X2s = X2;
+ __m128i X3s = X3;
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ X0 = _mm_add_epi32(X0s,X0);
+ X1 = _mm_add_epi32(X1s,X1);
+ X2 = _mm_add_epi32(X2s,X2);
+ X3 = _mm_add_epi32(X3s,X3);
+
+ __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3));
+ __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3));
+ __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32));
+ __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32));
+ _mm_storeu_ps(reinterpret_cast<float *>(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m))))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 4)))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 8)))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 12)))));
+
+ if (!(++_state.i[8])) {
+ ++_state.i[5]; // state reordered for SSE
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+#else
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
x0 = PLUS(x0,j0);
x1 = PLUS(x1,j1);
x2 = PLUS(x2,j2);
diff --git a/node/Salsa20.hpp b/node/Salsa20.hpp
index 84baf3da..7e4c1e53 100644
--- a/node/Salsa20.hpp
+++ b/node/Salsa20.hpp
@@ -12,6 +12,7 @@
#include <stdlib.h>
#include "Constants.hpp"
+#include "Utils.hpp"
#if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || defined(__WINDOWS__))
#define ZT_SALSA20_SSE 1
@@ -31,16 +32,17 @@ class Salsa20
public:
Salsa20() throw() {}
+ ~Salsa20() { Utils::burn(&_state,sizeof(_state)); }
+
/**
* @param key Key bits
* @param kbits Number of key bits: 128 or 256 (recommended)
* @param iv 64-bit initialization vector
- * @param rounds Number of rounds: 8, 12, or 20
*/
- Salsa20(const void *key,unsigned int kbits,const void *iv,unsigned int rounds)
+ Salsa20(const void *key,unsigned int kbits,const void *iv)
throw()
{
- init(key,kbits,iv,rounds);
+ init(key,kbits,iv);
}
/**
@@ -49,19 +51,28 @@ public:
* @param key Key bits
* @param kbits Number of key bits: 128 or 256 (recommended)
* @param iv 64-bit initialization vector
- * @param rounds Number of rounds: 8, 12, or 20
*/
- void init(const void *key,unsigned int kbits,const void *iv,unsigned int rounds)
+ void init(const void *key,unsigned int kbits,const void *iv)
+ throw();
+
+ /**
+ * Encrypt data using Salsa20/12
+ *
+ * @param in Input data
+ * @param out Output buffer
+ * @param bytes Length of data
+ */
+ void encrypt12(const void *in,void *out,unsigned int bytes)
throw();
/**
- * Encrypt data
+ * Encrypt data using Salsa20/20
*
* @param in Input data
* @param out Output buffer
* @param bytes Length of data
*/
- void encrypt(const void *in,void *out,unsigned int bytes)
+ void encrypt20(const void *in,void *out,unsigned int bytes)
throw();
/**
@@ -71,10 +82,23 @@ public:
* @param out Output buffer
* @param bytes Length of data
*/
- inline void decrypt(const void *in,void *out,unsigned int bytes)
+ inline void decrypt12(const void *in,void *out,unsigned int bytes)
+ throw()
+ {
+ encrypt12(in,out,bytes);
+ }
+
+ /**
+ * Decrypt data
+ *
+ * @param in Input data
+ * @param out Output buffer
+ * @param bytes Length of data
+ */
+ inline void decrypt20(const void *in,void *out,unsigned int bytes)
throw()
{
- encrypt(in,out,bytes);
+ encrypt20(in,out,bytes);
}
private:
@@ -84,7 +108,6 @@ private:
#endif // ZT_SALSA20_SSE
uint32_t i[16];
} _state;
- unsigned int _roundsDiv4;
};
} // namespace ZeroTier
diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp
index 7329322a..ce75eb03 100644
--- a/node/SelfAwareness.cpp
+++ b/node/SelfAwareness.cpp
@@ -36,6 +36,7 @@
#include "Topology.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
+#include "Switch.hpp"
// Entry timeout -- make it fairly long since this is just to prevent stale buildup
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 3600000
@@ -65,7 +66,8 @@ private:
};
SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
- RR(renv)
+ RR(renv),
+ _phy(32)
{
}
@@ -77,66 +79,62 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi
{
const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
+ // This would be weird, e.g. a public IP talking to 10.0.0.1, so just ignore it.
+ // If your network is this weird it's probably not reliable information.
+ if (scope != reporterPhysicalAddress.ipScope())
+ return;
+
+ // Some scopes we ignore, and global scope IPs are only used for this
+ // mechanism if they come from someone we trust (e.g. a root).
switch(scope) {
case InetAddress::IP_SCOPE_NONE:
case InetAddress::IP_SCOPE_LOOPBACK:
case InetAddress::IP_SCOPE_MULTICAST:
return;
case InetAddress::IP_SCOPE_GLOBAL:
- if ((!trusted)||(scope != reporterPhysicalAddress.ipScope()))
+ if (!trusted)
return;
break;
default:
- if (scope != reporterPhysicalAddress.ipScope())
- return;
break;
}
Mutex::Lock _l(_phy_m);
+ PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,reporterPhysicalAddress,scope)];
- PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,scope)];
-
- if ((now - entry.ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) {
+ if ( ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) {
entry.mySurface = myPhysicalAddress;
entry.ts = now;
- TRACE("learned physical address %s for scope %u as seen from %s(%s) (replaced <null>)",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str());
- } else if (entry.mySurface != myPhysicalAddress) {
- entry.mySurface = myPhysicalAddress;
- entry.ts = now;
- TRACE("learned physical address %s for scope %u as seen from %s(%s) (replaced %s, resetting all in scope)",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str(),entry.mySurface.toString().c_str());
+ TRACE("physical address %s for scope %u as seen from %s(%s) differs from %s, resetting paths in scope",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str(),entry.mySurface.toString().c_str());
- // Erase all entries (other than this one) for this scope to prevent thrashing
- // Note: we should probably not use 'entry' after this
+ // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing'
+ // due to multiple reports of endpoint change.
+ // Don't use 'entry' after this since hash table gets modified.
{
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
- if ((k->reporter != reporter)&&(k->scope == scope))
+ if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope))
_phy.erase(*k);
}
}
+ // Reset all paths within this scope
_ResetWithinScope rset(RR,now,(InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope &>(rset);
- // For all peers for whom we forgot an address, send a packet indirectly if
- // they are still considered alive so that we will re-establish direct links.
- SharedPtr<Peer> sn(RR->topology->getBestRoot());
- if (sn) {
- RemotePath *snp = sn->getBestPath(now);
- if (snp) {
- for(std::vector< SharedPtr<Peer> >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) {
- if ((*p)->alive(now)) {
- TRACE("sending indirect NOP to %s via %s(%s) to re-establish link",(*p)->address().toString().c_str(),sn->address().toString().c_str(),snp->address().toString().c_str());
- Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP);
- outp.armor((*p)->key(),true);
- snp->send(RR,outp.data(),outp.size(),now);
- }
- }
+ // Send a NOP to all peers for whom we forgot a path. This will cause direct
+ // links to be re-established if possible, possibly using a root server or some
+ // other relay.
+ for(std::vector< SharedPtr<Peer> >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) {
+ if ((*p)->activelyTransferringFrames(now)) {
+ Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP);
+ RR->sw->send(outp,true,0);
}
}
} else {
+ entry.mySurface = myPhysicalAddress;
entry.ts = now;
}
}
diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp
index 3133553e..400b05e6 100644
--- a/node/SelfAwareness.hpp
+++ b/node/SelfAwareness.hpp
@@ -69,14 +69,14 @@ private:
struct PhySurfaceKey
{
Address reporter;
+ InetAddress reporterPhysicalAddress;
InetAddress::IpScope scope;
- inline unsigned long hashCode() const throw() { return ((unsigned long)reporter.toInt() + (unsigned long)scope); }
-
PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {}
- PhySurfaceKey(const Address &r,InetAddress::IpScope s) : reporter(r),scope(s) {}
- inline bool operator<(const PhySurfaceKey &k) const throw() { return ((reporter < k.reporter) ? true : ((reporter == k.reporter) ? ((int)scope < (int)k.scope) : false)); }
- inline bool operator==(const PhySurfaceKey &k) const throw() { return ((reporter == k.reporter)&&(scope == k.scope)); }
+ PhySurfaceKey(const Address &r,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),reporterPhysicalAddress(ra),scope(s) {}
+
+ inline unsigned long hashCode() const throw() { return ((unsigned long)reporter.toInt() + (unsigned long)scope); }
+ inline bool operator==(const PhySurfaceKey &k) const throw() { return ((reporter == k.reporter)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); }
};
struct PhySurfaceEntry
{
diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp
index 4ecfa818..289c499f 100644
--- a/node/SharedPtr.hpp
+++ b/node/SharedPtr.hpp
@@ -64,20 +64,6 @@ public:
++obj->__refCount;
}
- SharedPtr(T *obj,bool runAwayFromZombies)
- throw() :
- _ptr(obj)
- {
- // HACK: this is used in "handlers" to take ownership of naked pointers,
- // an ugly pattern that really ought to be factored out.
- if (runAwayFromZombies) {
- if ((int)(++obj->__refCount) < 2) {
- --obj->__refCount;
- _ptr = (T *)0;
- }
- } else ++obj->__refCount;
- }
-
SharedPtr(const SharedPtr &sp)
throw() :
_ptr(sp._getAndInc())
@@ -105,6 +91,25 @@ public:
return *this;
}
+ /**
+ * Set to a naked pointer and increment its reference count
+ *
+ * This assumes this SharedPtr is NULL and that ptr is not a 'zombie.' No
+ * checks are performed.
+ *
+ * @param ptr Naked pointer to assign
+ */
+ inline void setToUnsafe(T *ptr)
+ {
+ ++ptr->__refCount;
+ _ptr = ptr;
+ }
+
+ /**
+ * Swap with another pointer 'for free' without ref count overhead
+ *
+ * @param with Pointer to swap with
+ */
inline void swap(SharedPtr &with)
throw()
{
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 9ea8ac49..74e2f4c6 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -45,6 +45,7 @@
#include "AntiRecursion.hpp"
#include "SelfAwareness.hpp"
#include "Packet.hpp"
+#include "Cluster.hpp"
namespace ZeroTier {
@@ -153,25 +154,84 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
MulticastGroup mg(to,0);
if (to.isBroadcast()) {
- if (
- (etherType == ZT_ETHERTYPE_ARP)&&
- (len >= 28)&&
- (
- (((const unsigned char *)data)[2] == 0x08)&&
- (((const unsigned char *)data)[3] == 0x00)&&
- (((const unsigned char *)data)[4] == 6)&&
- (((const unsigned char *)data)[5] == 4)&&
- (((const unsigned char *)data)[7] == 0x01)
- )
- ) {
- // Cram IPv4 IP into ADI field to make IPv4 ARP broadcast channel specific and scalable
- // Also: enableBroadcast() does not apply to ARP since it's required for IPv4
+ if ( (etherType == ZT_ETHERTYPE_ARP) && (len >= 28) && ((((const uint8_t *)data)[2] == 0x08)&&(((const uint8_t *)data)[3] == 0x00)&&(((const uint8_t *)data)[4] == 6)&&(((const uint8_t *)data)[5] == 4)&&(((const uint8_t *)data)[7] == 0x01)) ) {
+ /* IPv4 ARP is one of the few special cases that we impose upon what is
+ * otherwise a straightforward Ethernet switch emulation. Vanilla ARP
+ * is dumb old broadcast and simply doesn't scale. ZeroTier multicast
+ * groups have an additional field called ADI (additional distinguishing
+ * information) which was added specifically for ARP though it could
+ * be used for other things too. We then take ARP broadcasts and turn
+ * them into multicasts by stuffing the IP address being queried into
+ * the 32-bit ADI field. In practice this uses our multicast pub/sub
+ * system to implement a kind of extended/distributed ARP table. */
mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0));
} else if (!nconf->enableBroadcast()) {
// Don't transmit broadcasts if this network doesn't want them
TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id());
return;
}
+ } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) {
+ /* IPv6 NDP emulation on ZeroTier-RFC4193 addressed networks! This allows
+ * for multicast-free operation in IPv6 networks, which both improves
+ * performance and is friendlier to mobile and (especially) IoT devices.
+ * In the future there may be a no-multicast build option for embedded
+ * and IoT use and this will be the preferred addressing mode. Note that
+ * it plays nice with our L2 emulation philosophy and even with bridging.
+ * While "real" devices behind the bridge can't have ZT-RFC4193 addresses
+ * themselves, they can look these addresses up with NDP and it will
+ * work just fine. */
+ if ((reinterpret_cast<const uint8_t *>(data)[6] == 0x3a)&&(reinterpret_cast<const uint8_t *>(data)[40] == 0x87)) { // ICMPv6 neighbor solicitation
+ for(std::vector<InetAddress>::const_iterator sip(nconf->staticIps().begin()),sipend(nconf->staticIps().end());sip!=sipend;++sip) {
+ if ((sip->ss_family == AF_INET6)&&(Utils::ntoh((uint16_t)reinterpret_cast<const struct sockaddr_in6 *>(&(*sip))->sin6_port) == 88)) {
+ const uint8_t *my6 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&(*sip))->sin6_addr.s6_addr);
+ if ((my6[0] == 0xfd)&&(my6[9] == 0x99)&&(my6[10] == 0x93)) { // ZT-RFC4193 == fd__:____:____:____:__99:93__:____:____ / 88
+ const uint8_t *pkt6 = reinterpret_cast<const uint8_t *>(data) + 40 + 8;
+ unsigned int ptr = 0;
+ while (ptr != 11) {
+ if (pkt6[ptr] != my6[ptr])
+ break;
+ ++ptr;
+ }
+ if (ptr == 11) { // /88 matches an assigned address on this network
+ const Address atPeer(pkt6 + ptr,5);
+ if (atPeer != RR->identity.address()) {
+ const MAC atPeerMac(atPeer,network->id());
+ TRACE("ZT-RFC4193 NDP emulation: %.16llx: forging response for %s/%s",network->id(),atPeer.toString().c_str(),atPeerMac.toString().c_str());
+
+ uint8_t adv[72];
+ adv[0] = 0x60; adv[1] = 0x00; adv[2] = 0x00; adv[3] = 0x00;
+ adv[4] = 0x00; adv[5] = 0x20;
+ adv[6] = 0x3a; adv[7] = 0xff;
+ for(int i=0;i<16;++i) adv[8 + i] = pkt6[i];
+ for(int i=0;i<16;++i) adv[24 + i] = my6[i];
+ adv[40] = 0x88; adv[41] = 0x00;
+ adv[42] = 0x00; adv[43] = 0x00; // future home of checksum
+ adv[44] = 0x60; adv[45] = 0x00; adv[46] = 0x00; adv[47] = 0x00;
+ for(int i=0;i<16;++i) adv[48 + i] = pkt6[i];
+ adv[64] = 0x02; adv[65] = 0x01;
+ adv[66] = atPeerMac[0]; adv[67] = atPeerMac[1]; adv[68] = atPeerMac[2]; adv[69] = atPeerMac[3]; adv[70] = atPeerMac[4]; adv[71] = atPeerMac[5];
+
+ uint16_t pseudo_[36];
+ uint8_t *const pseudo = reinterpret_cast<uint8_t *>(pseudo_);
+ for(int i=0;i<32;++i) pseudo[i] = adv[8 + i];
+ pseudo[32] = 0x00; pseudo[33] = 0x00; pseudo[34] = 0x00; pseudo[35] = 0x20;
+ pseudo[36] = 0x00; pseudo[37] = 0x00; pseudo[38] = 0x00; pseudo[39] = 0x3a;
+ for(int i=0;i<32;++i) pseudo[40 + i] = adv[40 + i];
+ uint32_t checksum = 0;
+ for(int i=0;i<36;++i) checksum += Utils::hton(pseudo_[i]);
+ while ((checksum >> 16)) checksum = (checksum & 0xffff) + (checksum >> 16);
+ checksum = ~checksum;
+ adv[42] = (checksum >> 8) & 0xff;
+ adv[43] = checksum & 0xff;
+
+ RR->node->putFrame(network->id(),atPeerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72);
+ return; // stop processing: we have handled this frame with a spoofed local reply so no need to send it anywhere
+ }
+ }
+ }
+ }
+ }
+ }
}
/* Learn multicast groups for bridged-in hosts.
@@ -203,7 +263,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this
SharedPtr<Peer> toPeer(RR->topology->getPeer(toZT));
- const bool includeCom = ((!toPeer)||(toPeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true)));;
+ const bool includeCom = ( (nconf->isPrivate()) && (nconf->com()) && ((!toPeer)||(toPeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) );
if ((fromBridged)||(includeCom)) {
Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(network->id());
@@ -271,7 +331,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
SharedPtr<Peer> bridgePeer(RR->topology->getPeer(bridges[b]));
Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(network->id());
- if ((!bridgePeer)||(bridgePeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) {
+ if ( (nconf->isPrivate()) && (nconf->com()) && ((!bridgePeer)||(bridgePeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) ) {
outp.append((unsigned char)0x01); // 0x01 -- COM included
nconf->com().serialize(outp);
} else {
@@ -294,17 +354,18 @@ void Switch::send(const Packet &packet,bool encrypt,uint64_t nwid)
return;
}
+ //TRACE(">> %s to %s (%u bytes, encrypt==%d, nwid==%.16llx)",Packet::verbString(packet.verb()),packet.destination().toString().c_str(),packet.size(),(int)encrypt,nwid);
+
if (!_trySend(packet,encrypt,nwid)) {
Mutex::Lock _l(_txQueue_m);
_txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt,nwid));
}
}
-bool Switch::unite(const Address &p1,const Address &p2,bool force)
+bool Switch::unite(const Address &p1,const Address &p2)
{
if ((p1 == RR->identity.address())||(p2 == RR->identity.address()))
return false;
-
SharedPtr<Peer> p1p = RR->topology->getPeer(p1);
if (!p1p)
return false;
@@ -314,14 +375,6 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
const uint64_t now = RR->node->now();
- {
- Mutex::Lock _l(_lastUniteAttempt_m);
- uint64_t &luts = _lastUniteAttempt[_LastUniteKey(p1,p2)];
- if (((now - luts) < ZT_MIN_UNITE_INTERVAL)&&(!force))
- return false;
- luts = now;
- }
-
std::pair<InetAddress,InetAddress> cg(Peer::findCommonGround(*p1p,*p2p,now));
if ((!(cg.first))||(cg.first.ipScope() != cg.second.ipScope()))
return false;
@@ -382,7 +435,7 @@ void Switch::rendezvous(const SharedPtr<Peer> &peer,const InetAddress &localAddr
{
TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str());
const uint64_t now = RR->node->now();
- peer->attemptToContactAt(RR,localAddr,atAddr,now);
+ peer->sendHELLO(RR,localAddr,atAddr,now,2); // first attempt: send low-TTL packet to 'open' local NAT
{
Mutex::Lock _l(_contactQueue_m);
_contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,localAddr,atAddr));
@@ -422,7 +475,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr<Peer> &peer)
{ // finish processing any packets waiting on peer's public key / identity
Mutex::Lock _l(_rxQueue_m);
for(std::list< SharedPtr<IncomingPacket> >::iterator rxi(_rxQueue.begin());rxi!=_rxQueue.end();) {
- if ((*rxi)->tryDecode(RR))
+ if ((*rxi)->tryDecode(RR,false))
_rxQueue.erase(rxi++);
else ++rxi;
}
@@ -448,21 +501,21 @@ unsigned long Switch::doTimerTasks(uint64_t now)
Mutex::Lock _l(_contactQueue_m);
for(std::list<ContactQueueEntry>::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) {
if (now >= qi->fireAtTime) {
- if ((!qi->peer->alive(now))||(qi->peer->hasActiveDirectPath(now))) {
- // Cancel attempt if we've already connected or peer is no longer "alive"
+ if (qi->peer->hasActiveDirectPath(now)) {
+ // Cancel if connection has succeeded
_contactQueue.erase(qi++);
continue;
} else {
if (qi->strategyIteration == 0) {
// First strategy: send packet directly to destination
- qi->peer->attemptToContactAt(RR,qi->localAddr,qi->inaddr,now);
- } else if (qi->strategyIteration <= 4) {
- // Strategies 1-4: try escalating ports for symmetric NATs that remap sequentially
+ qi->peer->sendHELLO(RR,qi->localAddr,qi->inaddr,now);
+ } else if (qi->strategyIteration <= 3) {
+ // Strategies 1-3: try escalating ports for symmetric NATs that remap sequentially
InetAddress tmpaddr(qi->inaddr);
int p = (int)qi->inaddr.port() + qi->strategyIteration;
if (p < 0xffff) {
tmpaddr.setPort((unsigned int)p);
- qi->peer->attemptToContactAt(RR,qi->localAddr,tmpaddr,now);
+ qi->peer->sendHELLO(RR,qi->localAddr,tmpaddr,now);
} else qi->strategyIteration = 5;
} else {
// All strategies tried, expire entry
@@ -545,7 +598,7 @@ unsigned long Switch::doTimerTasks(uint64_t now)
_LastUniteKey *k = (_LastUniteKey *)0;
uint64_t *v = (uint64_t *)0;
while (i.next(k,v)) {
- if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 16))
+ if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 8))
_lastUniteAttempt.erase(*k);
}
}
@@ -567,6 +620,13 @@ void Switch::_handleRemotePacketFragment(const InetAddress &localAddr,const Inet
// It wouldn't hurt anything, just redundant and unnecessary.
SharedPtr<Peer> relayTo = RR->topology->getPeer(destination);
if ((!relayTo)||(!relayTo->send(RR,fragment.data(),fragment.size(),RR->node->now()))) {
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster) {
+ RR->cluster->sendViaCluster(Address(),destination,fragment.data(),fragment.size(),false);
+ return;
+ }
+#endif
+
// Don't know peer or no direct path -- so relay via root server
relayTo = RR->topology->getBestRoot();
if (relayTo)
@@ -614,7 +674,7 @@ void Switch::_handleRemotePacketFragment(const InetAddress &localAddr,const Inet
packet->append(dq.frags[f - 1].payload(),dq.frags[f - 1].payloadLength());
_defragQueue.erase(pid); // dq no longer valid after this
- if (!packet->tryDecode(RR)) {
+ if (!packet->tryDecode(RR,false)) {
Mutex::Lock _l(_rxQueue_m);
_rxQueue.push_back(packet);
}
@@ -626,11 +686,17 @@ void Switch::_handleRemotePacketFragment(const InetAddress &localAddr,const Inet
void Switch::_handleRemotePacketHead(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len)
{
- SharedPtr<IncomingPacket> packet(new IncomingPacket(data,len,localAddr,fromAddr,RR->node->now()));
+ const uint64_t now = RR->node->now();
+ SharedPtr<IncomingPacket> packet(new IncomingPacket(data,len,localAddr,fromAddr,now));
Address source(packet->source());
Address destination(packet->destination());
+ // Catch this and toss it -- it would never work, but it could happen if we somehow
+ // mistakenly guessed an address we're bound to as a destination for another peer.
+ if (source == RR->identity.address())
+ return;
+
//TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size());
if (destination != RR->identity.address()) {
@@ -639,13 +705,32 @@ void Switch::_handleRemotePacketHead(const InetAddress &localAddr,const InetAddr
packet->incrementHops();
SharedPtr<Peer> relayTo = RR->topology->getPeer(destination);
- if ((relayTo)&&((relayTo->send(RR,packet->data(),packet->size(),RR->node->now())))) {
- unite(source,destination,false);
+ if ((relayTo)&&((relayTo->send(RR,packet->data(),packet->size(),now)))) {
+ Mutex::Lock _l(_lastUniteAttempt_m);
+ uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)];
+ if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) {
+ luts = now;
+ unite(source,destination);
+ }
} else {
- // Don't know peer or no direct path -- so relay via root server
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster) {
+ bool shouldUnite;
+ {
+ Mutex::Lock _l(_lastUniteAttempt_m);
+ uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)];
+ shouldUnite = ((now - luts) >= ZT_MIN_UNITE_INTERVAL);
+ if (shouldUnite)
+ luts = now;
+ }
+ RR->cluster->sendViaCluster(source,destination,packet->data(),packet->size(),shouldUnite);
+ return;
+ }
+#endif
+
relayTo = RR->topology->getBestRoot(&source,1,true);
if (relayTo)
- relayTo->send(RR,packet->data(),packet->size(),RR->node->now());
+ relayTo->send(RR,packet->data(),packet->size(),now);
}
} else {
TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet->source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str());
@@ -660,7 +745,7 @@ void Switch::_handleRemotePacketHead(const InetAddress &localAddr,const InetAddr
if (!dq.creationTime) {
// If we have no other fragments yet, create an entry and save the head
- dq.creationTime = RR->node->now();
+ dq.creationTime = now;
dq.frag0 = packet;
dq.totalFragments = 0; // 0 == unknown, waiting for Packet::Fragment
dq.haveFragments = 1; // head is first bit (left to right)
@@ -677,7 +762,7 @@ void Switch::_handleRemotePacketHead(const InetAddress &localAddr,const InetAddr
packet->append(dq.frags[f - 1].payload(),dq.frags[f - 1].payloadLength());
_defragQueue.erase(pid); // dq no longer valid after this
- if (!packet->tryDecode(RR)) {
+ if (!packet->tryDecode(RR,false)) {
Mutex::Lock _l(_rxQueue_m);
_rxQueue.push_back(packet);
}
@@ -688,7 +773,7 @@ void Switch::_handleRemotePacketHead(const InetAddress &localAddr,const InetAddr
} // else this is a duplicate head, ignore
} else {
// Packet is unfragmented, so just process it
- if (!packet->tryDecode(RR)) {
+ if (!packet->tryDecode(RR,false)) {
Mutex::Lock _l(_rxQueue_m);
_rxQueue.push_back(packet);
}
@@ -726,17 +811,20 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
return false; // sanity check: unconfigured network? why are we trying to talk to it?
}
- RemotePath *viaPath = peer->getBestPath(now);
+ Path *viaPath = peer->getBestPath(now);
SharedPtr<Peer> relay;
if (!viaPath) {
// See if this network has a preferred relay (if packet has an associated network)
if (nconf) {
- unsigned int latency = ~((unsigned int)0);
+ unsigned int bestq = ~((unsigned int)0);
for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(nconf->relays().begin());r!=nconf->relays().end();++r) {
if (r->first != peer->address()) {
SharedPtr<Peer> rp(RR->topology->getPeer(r->first));
- if ((rp)&&(rp->hasActiveDirectPath(now))&&(rp->latency() <= latency))
+ const unsigned int q = rp->relayQuality(now);
+ if ((rp)&&(q < bestq)) { // SUBTILE: < == don't use these if they are nil quality (unsigned int max), instead use a root
+ bestq = q;
rp.swap(relay);
+ }
}
}
}
diff --git a/node/Switch.hpp b/node/Switch.hpp
index cf8420cf..1964d1ee 100644
--- a/node/Switch.hpp
+++ b/node/Switch.hpp
@@ -117,15 +117,10 @@ public:
* This only works if both peers are known, with known working direct
* links to this peer. The best link for each peer is sent to the other.
*
- * A rate limiter is in effect via the _lastUniteAttempt map. If force
- * is true, a unite attempt is made even if one has been made less than
- * ZT_MIN_UNITE_INTERVAL milliseconds ago.
- *
* @param p1 One of two peers (order doesn't matter)
* @param p2 Second of pair
- * @param force If true, send now regardless of interval
*/
- bool unite(const Address &p1,const Address &p2,bool force);
+ bool unite(const Address &p1,const Address &p2);
/**
* Attempt NAT traversal to peer at a given physical address
diff --git a/node/Topology.cpp b/node/Topology.cpp
index 908acbc8..d94975dd 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -28,13 +28,21 @@
#include "Constants.hpp"
#include "Topology.hpp"
#include "RuntimeEnvironment.hpp"
-#include "Defaults.hpp"
-#include "Dictionary.hpp"
#include "Node.hpp"
+#include "Network.hpp"
+#include "NetworkConfig.hpp"
#include "Buffer.hpp"
namespace ZeroTier {
+// 2015-11-16 -- The Fabulous Four (should have named them after Beatles!)
+//#define ZT_DEFAULT_WORLD_LENGTH 494
+//static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x51,0x11,0x70,0xb2,0xfb,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x80,0x31,0xa4,0x65,0x95,0x45,0x06,0x1c,0xfb,0xc2,0x4e,0x5d,0xe7,0x0a,0x40,0x7a,0x97,0xce,0x36,0xa2,0x3d,0x05,0xca,0x87,0xc7,0x59,0x27,0x5c,0x8b,0x0d,0x4c,0xb4,0xbb,0x26,0x2f,0x77,0x17,0x5e,0xb7,0x4d,0xb8,0xd3,0xb4,0xe9,0x23,0x5d,0xcc,0xa2,0x71,0xa8,0xdf,0xf1,0x23,0xa3,0xb2,0x66,0x74,0xea,0xe5,0xdc,0x8d,0xef,0xd3,0x0a,0xa9,0xac,0xcb,0xda,0x93,0xbd,0x6c,0xcd,0x43,0x1d,0xa7,0x98,0x6a,0xde,0x70,0xc0,0xc6,0x1c,0xaf,0xf0,0xfd,0x7f,0x8a,0xb9,0x76,0x13,0xe1,0xde,0x4f,0xf3,0xd6,0x13,0x04,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x01,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x01,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09};
+
+// 2015-11-20 -- Alice and Bob are live, and we're now IPv6 dual-stack!
+#define ZT_DEFAULT_WORLD_LENGTH 792
+static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x51,0x26,0x6f,0x7c,0x8a,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0xe8,0x0a,0xf5,0xbc,0xf8,0x3d,0x97,0xcd,0xc3,0xf8,0xe2,0x41,0x16,0x42,0x0f,0xc7,0x76,0x8e,0x07,0xf3,0x7e,0x9e,0x7d,0x1b,0xb3,0x23,0x21,0x79,0xce,0xb9,0xd0,0xcb,0xb5,0x94,0x7b,0x89,0x21,0x57,0x72,0xf6,0x70,0xa1,0xdd,0x67,0x38,0xcf,0x45,0x45,0xc2,0x8d,0x46,0xec,0x00,0x2c,0xe0,0x2a,0x63,0x3f,0x63,0x8d,0x33,0x08,0x51,0x07,0x77,0x81,0x5b,0x32,0x49,0xae,0x87,0x89,0xcf,0x31,0xaa,0x41,0xf1,0x52,0x97,0xdc,0xa2,0x55,0xe1,0x4a,0x6e,0x3c,0x04,0xf0,0x4f,0x8a,0x0e,0xe9,0xca,0xec,0x24,0x30,0x04,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09};
+
Topology::Topology(const RuntimeEnvironment *renv) :
RR(renv),
_amRoot(false)
@@ -43,130 +51,110 @@ Topology::Topology(const RuntimeEnvironment *renv) :
const uint8_t *all = reinterpret_cast<const uint8_t *>(alls.data());
RR->node->dataStoreDelete("peers.save");
+ Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE> *deserializeBuf = new Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE>();
unsigned int ptr = 0;
while ((ptr + 4) < alls.size()) {
- // Each Peer serializes itself prefixed by a record length (not including the size of the length itself)
- unsigned int reclen = (unsigned int)all[ptr] & 0xff;
- reclen <<= 8;
- reclen |= (unsigned int)all[ptr + 1] & 0xff;
- reclen <<= 8;
- reclen |= (unsigned int)all[ptr + 2] & 0xff;
- reclen <<= 8;
- reclen |= (unsigned int)all[ptr + 3] & 0xff;
-
- if (((ptr + reclen) > alls.size())||(reclen > ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE))
- break;
-
try {
+ const unsigned int reclen = ( // each Peer serialized record is prefixed by a record length
+ ((((unsigned int)all[ptr]) & 0xff) << 24) |
+ ((((unsigned int)all[ptr + 1]) & 0xff) << 16) |
+ ((((unsigned int)all[ptr + 2]) & 0xff) << 8) |
+ (((unsigned int)all[ptr + 3]) & 0xff)
+ );
unsigned int pos = 0;
- SharedPtr<Peer> p(Peer::deserializeNew(RR->identity,Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE>(all + ptr,reclen),pos));
- if (pos != reclen)
- break;
+ deserializeBuf->copyFrom(all + ptr,reclen + 4);
+ SharedPtr<Peer> p(Peer::deserializeNew(RR->identity,*deserializeBuf,pos));
ptr += pos;
- if ((p)&&(p->address() != RR->identity.address())) {
- _peers[p->address()] = p;
- } else {
+ if (!p)
break; // stop if invalid records
- }
- } catch (std::exception &exc) {
- break;
+ if (p->address() != RR->identity.address())
+ _peers.set(p->address(),p);
} catch ( ... ) {
break; // stop if invalid records
}
}
+ delete deserializeBuf;
clean(RR->node->now());
-}
-
-Topology::~Topology()
-{
- Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE> pbuf;
- std::string all;
- Address *a = (Address *)0;
- SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
- Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
- while (i.next(a,p)) {
- if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) {
- pbuf.clear();
- try {
- (*p)->serialize(pbuf);
- try {
- all.append((const char *)pbuf.data(),pbuf.size());
- } catch ( ... ) {
- return; // out of memory? just skip
- }
- } catch ( ... ) {} // peer too big? shouldn't happen, but it so skip
+ std::string dsWorld(RR->node->dataStoreGet("world"));
+ World cachedWorld;
+ if (dsWorld.length() > 0) {
+ try {
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp(dsWorld.data(),(unsigned int)dsWorld.length());
+ cachedWorld.deserialize(dswtmp,0);
+ } catch ( ... ) {
+ cachedWorld = World(); // clear if cached world is invalid
}
}
-
- RR->node->dataStorePut("peers.save",all,true);
-}
-
-void Topology::setRootServers(const std::map< Identity,std::vector<InetAddress> > &sn)
-{
- Mutex::Lock _l(_lock);
-
- if (_roots == sn)
- return; // no change
-
- _roots = sn;
- _rootAddresses.clear();
- _rootPeers.clear();
- const uint64_t now = RR->node->now();
-
- for(std::map< Identity,std::vector<InetAddress> >::const_iterator i(sn.begin());i!=sn.end();++i) {
- if (i->first != RR->identity) { // do not add self as a peer
- SharedPtr<Peer> &p = _peers[i->first.address()];
- if (!p)
- p = SharedPtr<Peer>(new Peer(RR->identity,i->first));
- for(std::vector<InetAddress>::const_iterator j(i->second.begin());j!=i->second.end();++j)
- p->addPath(RemotePath(InetAddress(),*j,true),now);
- p->use(now);
- _rootPeers.push_back(p);
- }
- _rootAddresses.push_back(i->first.address());
+ World defaultWorld;
+ {
+ Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH);
+ defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top
}
-
- std::sort(_rootAddresses.begin(),_rootAddresses.end());
-
- _amRoot = (_roots.find(RR->identity) != _roots.end());
+ if (cachedWorld.shouldBeReplacedBy(defaultWorld,false)) {
+ _setWorld(defaultWorld);
+ if (dsWorld.length() > 0)
+ RR->node->dataStoreDelete("world");
+ } else _setWorld(cachedWorld);
}
-void Topology::setRootServers(const Dictionary &sn)
+Topology::~Topology()
{
- std::map< Identity,std::vector<InetAddress> > m;
- for(Dictionary::const_iterator d(sn.begin());d!=sn.end();++d) {
- if ((d->first.length() == ZT_ADDRESS_LENGTH_HEX)&&(d->second.length() > 0)) {
- try {
- Dictionary snspec(d->second);
- std::vector<InetAddress> &a = m[Identity(snspec.get("id",""))];
- std::string udp(snspec.get("udp",std::string()));
- if (udp.length() > 0)
- a.push_back(InetAddress(udp));
- } catch ( ... ) {
- TRACE("root server list contained invalid entry for: %s",d->first.c_str());
+ Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE> *pbuf = 0;
+ try {
+ pbuf = new Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE>();
+ std::string all;
+
+ Address *a = (Address *)0;
+ SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+ Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
+ while (i.next(a,p)) {
+ if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) {
+ pbuf->clear();
+ try {
+ (*p)->serialize(*pbuf);
+ try {
+ all.append((const char *)pbuf->data(),pbuf->size());
+ } catch ( ... ) {
+ return; // out of memory? just skip
+ }
+ } catch ( ... ) {} // peer too big? shouldn't happen, but it so skip
}
}
+
+ RR->node->dataStorePut("peers.save",all,true);
+
+ delete pbuf;
+ } catch ( ... ) {
+ delete pbuf;
}
- this->setRootServers(m);
}
SharedPtr<Peer> Topology::addPeer(const SharedPtr<Peer> &peer)
{
- if (peer->address() == RR->identity.address()) {
- TRACE("BUG: addNewPeer() caught and ignored attempt to add peer for self");
- throw std::logic_error("cannot add peer for self");
+#ifdef ZT_TRACE
+ if ((!peer)||(peer->address() == RR->identity.address())) {
+ if (!peer)
+ fprintf(stderr,"FATAL BUG: addPeer() caught attempt to add NULL peer" ZT_EOL_S);
+ else fprintf(stderr,"FATAL BUG: addPeer() caught attempt to add peer for self" ZT_EOL_S);
+ abort();
+ }
+#endif
+
+ SharedPtr<Peer> np;
+ {
+ Mutex::Lock _l(_lock);
+ SharedPtr<Peer> &hp = _peers[peer->address()];
+ if (!hp)
+ hp = peer;
+ np = hp;
}
- const uint64_t now = RR->node->now();
- Mutex::Lock _l(_lock);
-
- SharedPtr<Peer> &p = _peers.set(peer->address(),peer);
- p->use(now);
- _saveIdentity(p->identity());
+ np->use(RR->node->now());
+ saveIdentity(np->identity());
- return p;
+ return np;
}
SharedPtr<Peer> Topology::getPeer(const Address &zta)
@@ -176,33 +164,58 @@ SharedPtr<Peer> Topology::getPeer(const Address &zta)
return SharedPtr<Peer>();
}
- const uint64_t now = RR->node->now();
- Mutex::Lock _l(_lock);
+ {
+ Mutex::Lock _l(_lock);
+ const SharedPtr<Peer> *const ap = _peers.get(zta);
+ if (ap) {
+ (*ap)->use(RR->node->now());
+ return *ap;
+ }
+ }
- SharedPtr<Peer> &ap = _peers[zta];
+ try {
+ Identity id(_getIdentity(zta));
+ if (id) {
+ SharedPtr<Peer> np(new Peer(RR->identity,id));
+ {
+ Mutex::Lock _l(_lock);
+ SharedPtr<Peer> &ap = _peers[zta];
+ if (!ap)
+ ap.swap(np);
+ ap->use(RR->node->now());
+ return ap;
+ }
+ }
+ } catch ( ... ) {
+ fprintf(stderr,"EXCEPTION in getPeer() part 2\n");
+ abort();
+ } // invalid identity on disk?
+
+ return SharedPtr<Peer>();
+}
- if (ap) {
- ap->use(now);
- return ap;
+Identity Topology::getIdentity(const Address &zta)
+{
+ {
+ Mutex::Lock _l(_lock);
+ const SharedPtr<Peer> *const ap = _peers.get(zta);
+ if (ap)
+ return (*ap)->identity();
}
+ return _getIdentity(zta);
+}
- Identity id(_getIdentity(zta));
+void Topology::saveIdentity(const Identity &id)
+{
if (id) {
- try {
- ap = SharedPtr<Peer>(new Peer(RR->identity,id));
- ap->use(now);
- return ap;
- } catch ( ... ) {} // invalid identity?
+ char p[128];
+ Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)id.address().toInt());
+ RR->node->dataStorePut(p,id.toString(false),false);
}
-
- _peers.erase(zta);
-
- return SharedPtr<Peer>();
}
SharedPtr<Peer> Topology::getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid)
{
- SharedPtr<Peer> bestRoot;
const uint64_t now = RR->node->now();
Mutex::Lock _l(_lock);
@@ -212,97 +225,92 @@ SharedPtr<Peer> Topology::getBestRoot(const Address *avoid,unsigned int avoidCou
* causes packets searching for a route to pretty much literally
* circumnavigate the globe rather than bouncing between just two. */
- if (_rootAddresses.size() > 1) { // gotta be one other than me for this to work
- std::vector<Address>::const_iterator sna(std::find(_rootAddresses.begin(),_rootAddresses.end(),RR->identity.address()));
- if (sna != _rootAddresses.end()) { // sanity check -- _amRoot should've been false in this case
- for(;;) {
- if (++sna == _rootAddresses.end())
- sna = _rootAddresses.begin(); // wrap around at end
- if (*sna != RR->identity.address()) { // pick one other than us -- starting from me+1 in sorted set order
- SharedPtr<Peer> *p = _peers.get(*sna);
- if ((p)&&((*p)->hasActiveDirectPath(now))) {
- bestRoot = *p;
- break;
- }
+ for(unsigned long p=0;p<_rootAddresses.size();++p) {
+ if (_rootAddresses[p] == RR->identity.address()) {
+ for(unsigned long q=1;q<_rootAddresses.size();++q) {
+ const SharedPtr<Peer> *const nextsn = _peers.get(_rootAddresses[(p + q) % _rootAddresses.size()]);
+ if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now))) {
+ (*nextsn)->use(now);
+ return *nextsn;
}
}
+ break;
}
}
+
} else {
/* If I am not a root server, the best root server is the active one with
- * the lowest latency. */
+ * the lowest quality score. (lower == better) */
- unsigned int l,bestLatency = 65536;
- uint64_t lds,ldr;
+ unsigned int bestQualityOverall = ~((unsigned int)0);
+ unsigned int bestQualityNotAvoid = ~((unsigned int)0);
+ const SharedPtr<Peer> *bestOverall = (const SharedPtr<Peer> *)0;
+ const SharedPtr<Peer> *bestNotAvoid = (const SharedPtr<Peer> *)0;
- // First look for a best root by comparing latencies, but exclude
- // root servers that have not responded to direct messages in order to
- // try to exclude any that are dead or unreachable.
- for(std::vector< SharedPtr<Peer> >::const_iterator sn(_rootPeers.begin());sn!=_rootPeers.end();) {
- // Skip explicitly avoided relays
+ for(std::vector< SharedPtr<Peer> >::const_iterator r(_rootPeers.begin());r!=_rootPeers.end();++r) {
+ bool avoiding = false;
for(unsigned int i=0;i<avoidCount;++i) {
- if (avoid[i] == (*sn)->address())
- goto keep_searching_for_roots;
- }
-
- // Skip possibly comatose or unreachable relays
- lds = (*sn)->lastDirectSend();
- ldr = (*sn)->lastDirectReceive();
- if ((lds)&&(lds > ldr)&&((lds - ldr) > ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD))
- goto keep_searching_for_roots;
-
- if ((*sn)->hasActiveDirectPath(now)) {
- l = (*sn)->latency();
- if (bestRoot) {
- if ((l)&&(l < bestLatency)) {
- bestLatency = l;
- bestRoot = *sn;
- }
- } else {
- if (l)
- bestLatency = l;
- bestRoot = *sn;
+ if (avoid[i] == (*r)->address()) {
+ avoiding = true;
+ break;
}
}
+ const unsigned int q = (*r)->relayQuality(now);
+ if (q <= bestQualityOverall) {
+ bestQualityOverall = q;
+ bestOverall = &(*r);
+ }
+ if ((!avoiding)&&(q <= bestQualityNotAvoid)) {
+ bestQualityNotAvoid = q;
+ bestNotAvoid = &(*r);
+ }
+ }
-keep_searching_for_roots:
- ++sn;
+ if (bestNotAvoid) {
+ (*bestNotAvoid)->use(now);
+ return *bestNotAvoid;
+ } else if ((!strictAvoid)&&(bestOverall)) {
+ (*bestOverall)->use(now);
+ return *bestOverall;
}
- if (bestRoot) {
- bestRoot->use(now);
- return bestRoot;
- } else if (strictAvoid)
- return SharedPtr<Peer>();
-
- // If we have nothing from above, just pick one without avoidance criteria.
- for(std::vector< SharedPtr<Peer> >::const_iterator sn=_rootPeers.begin();sn!=_rootPeers.end();++sn) {
- if ((*sn)->hasActiveDirectPath(now)) {
- unsigned int l = (*sn)->latency();
- if (bestRoot) {
- if ((l)&&(l < bestLatency)) {
- bestLatency = l;
- bestRoot = *sn;
- }
- } else {
- if (l)
- bestLatency = l;
- bestRoot = *sn;
- }
+ }
+
+ return SharedPtr<Peer>();
+}
+
+bool Topology::isUpstream(const Identity &id) const
+{
+ if (isRoot(id))
+ return true;
+ std::vector< SharedPtr<Network> > nws(RR->node->allNetworks());
+ for(std::vector< SharedPtr<Network> >::const_iterator nw(nws.begin());nw!=nws.end();++nw) {
+ SharedPtr<NetworkConfig> nc((*nw)->config2());
+ if (nc) {
+ for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(nc->relays().begin());r!=nc->relays().end();++r) {
+ if (r->first == id.address())
+ return true;
}
}
}
-
- if (bestRoot)
- bestRoot->use(now);
- return bestRoot;
+ return false;
}
-bool Topology::isRoot(const Identity &id) const
- throw()
+bool Topology::worldUpdateIfValid(const World &newWorld)
{
Mutex::Lock _l(_lock);
- return (_roots.count(id) != 0);
+ if (_world.shouldBeReplacedBy(newWorld,true)) {
+ _setWorld(newWorld);
+ try {
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp;
+ newWorld.serialize(dswtmp,false);
+ RR->node->dataStorePut("world",dswtmp.data(),dswtmp.size(),false);
+ } catch ( ... ) {
+ RR->node->dataStoreDelete("world");
+ }
+ return true;
+ }
+ return false;
}
void Topology::clean(uint64_t now)
@@ -320,24 +328,6 @@ void Topology::clean(uint64_t now)
}
}
-bool Topology::authenticateRootTopology(const Dictionary &rt)
-{
- try {
- std::string signer(rt.signingIdentity());
- if (!signer.length())
- return false;
- Identity signerId(signer);
- std::map< Address,Identity >::const_iterator authority(ZT_DEFAULTS.rootTopologyAuthorities.find(signerId.address()));
- if (authority == ZT_DEFAULTS.rootTopologyAuthorities.end())
- return false;
- if (signerId != authority->second)
- return false;
- return rt.verify(authority->second);
- } catch ( ... ) {
- return false;
- }
-}
-
Identity Topology::_getIdentity(const Address &zta)
{
char p[128];
@@ -351,12 +341,27 @@ Identity Topology::_getIdentity(const Address &zta)
return Identity();
}
-void Topology::_saveIdentity(const Identity &id)
+void Topology::_setWorld(const World &newWorld)
{
- if (id) {
- char p[128];
- Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)id.address().toInt());
- RR->node->dataStorePut(p,id.toString(false),false);
+ // assumed _lock is locked (or in constructor)
+ _world = newWorld;
+ _amRoot = false;
+ _rootAddresses.clear();
+ _rootPeers.clear();
+ for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
+ _rootAddresses.push_back(r->identity.address());
+ if (r->identity.address() == RR->identity.address()) {
+ _amRoot = true;
+ } else {
+ SharedPtr<Peer> *rp = _peers.get(r->identity.address());
+ if (rp) {
+ _rootPeers.push_back(*rp);
+ } else {
+ SharedPtr<Peer> newrp(new Peer(RR->identity,r->identity));
+ _peers.set(r->identity.address(),newrp);
+ _rootPeers.push_back(newrp);
+ }
+ }
}
}
diff --git a/node/Topology.hpp b/node/Topology.hpp
index 4df545e1..07daa276 100644
--- a/node/Topology.hpp
+++ b/node/Topology.hpp
@@ -31,10 +31,10 @@
#include <stdio.h>
#include <string.h>
-#include <map>
#include <vector>
#include <stdexcept>
#include <algorithm>
+#include <utility>
#include "Constants.hpp"
@@ -43,8 +43,8 @@
#include "Peer.hpp"
#include "Mutex.hpp"
#include "InetAddress.hpp"
-#include "Dictionary.hpp"
#include "Hashtable.hpp"
+#include "World.hpp"
namespace ZeroTier {
@@ -60,21 +60,6 @@ public:
~Topology();
/**
- * @param sn Root server identities and addresses
- */
- void setRootServers(const std::map< Identity,std::vector<InetAddress> > &sn);
-
- /**
- * Set up root servers for this network
- *
- * This performs no signature verification of any kind. The caller must
- * check the signature of the root topology dictionary first.
- *
- * @param sn 'rootservers' key from root-topology Dictionary (deserialized as Dictionary)
- */
- void setRootServers(const Dictionary &sn);
-
- /**
* Add a peer to database
*
* This will not replace existing peers. In that case the existing peer
@@ -94,23 +79,48 @@ public:
SharedPtr<Peer> getPeer(const Address &zta);
/**
- * @return Vector of peers that are root servers
+ * Get a peer only if it is presently in memory (no disk cache)
+ *
+ * This also does not update the lastUsed() time for peers, which means
+ * that it won't prevent them from falling out of RAM. This is currently
+ * used in the Cluster code to update peer info without forcing all peers
+ * across the entire cluster to remain in memory cache.
+ *
+ * @param zta ZeroTier address
*/
- inline std::vector< SharedPtr<Peer> > rootPeers() const
+ inline SharedPtr<Peer> getPeerNoCache(const Address &zta)
{
Mutex::Lock _l(_lock);
- return _rootPeers;
+ const SharedPtr<Peer> *const ap = _peers.get(zta);
+ if (ap)
+ return *ap;
+ return SharedPtr<Peer>();
}
/**
+ * Get the identity of a peer
+ *
+ * @param zta ZeroTier address of peer
+ * @return Identity or NULL Identity if not found
+ */
+ Identity getIdentity(const Address &zta);
+
+ /**
+ * Cache an identity
+ *
+ * This is done automatically on addPeer(), and so is only useful for
+ * cluster identity replication.
+ *
+ * @param id Identity to cache
+ */
+ void saveIdentity(const Identity &id);
+
+ /**
* Get the current favorite root server
*
* @return Root server with lowest latency or NULL if none
*/
- inline SharedPtr<Peer> getBestRoot()
- {
- return getBestRoot((const Address *)0,0,false);
- }
+ inline SharedPtr<Peer> getBestRoot() { return getBestRoot((const Address *)0,0,false); }
/**
* Get the best root server, avoiding root servers listed in an array
@@ -128,10 +138,19 @@ public:
/**
* @param id Identity to check
- * @return True if this is a designated root server
+ * @return True if this is a designated root server in this world
*/
- bool isRoot(const Identity &id) const
- throw();
+ inline bool isRoot(const Identity &id) const
+ {
+ Mutex::Lock _l(_lock);
+ return (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end());
+ }
+
+ /**
+ * @param id Identity to check
+ * @return True if this is a root server or a network preferred relay from one of our networks
+ */
+ bool isUpstream(const Identity &id) const;
/**
* @return Vector of root server addresses
@@ -143,11 +162,61 @@ public:
}
/**
+ * @return Current World (copy)
+ */
+ inline World world() const
+ {
+ Mutex::Lock _l(_lock);
+ return _world;
+ }
+
+ /**
+ * @return Current world ID
+ */
+ inline uint64_t worldId() const
+ {
+ return _world.id(); // safe to read without lock, and used from within eachPeer() so don't lock
+ }
+
+ /**
+ * @return Current world timestamp
+ */
+ inline uint64_t worldTimestamp() const
+ {
+ return _world.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock
+ }
+
+ /**
+ * Validate new world and update if newer and signature is okay
+ *
+ * @param newWorld Potential new world definition revision
+ * @return True if an update actually occurred
+ */
+ bool worldUpdateIfValid(const World &newWorld);
+
+ /**
* Clean and flush database
*/
void clean(uint64_t now);
/**
+ * @param now Current time
+ * @return Number of peers with active direct paths
+ */
+ inline unsigned long countActive(uint64_t now) const
+ {
+ unsigned long cnt = 0;
+ Mutex::Lock _l(_lock);
+ Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
+ Address *a = (Address *)0;
+ SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+ while (i.next(a,p)) {
+ cnt += (unsigned long)((*p)->hasActiveDirectPath(now));
+ }
+ return cnt;
+ }
+
+ /**
* Apply a function or function object to all peers
*
* Note: explicitly template this by reference if you want the object
@@ -167,12 +236,19 @@ public:
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
- while (i.next(a,p))
- f(*this,*p);
+ while (i.next(a,p)) {
+#ifdef ZT_TRACE
+ if (!(*p)) {
+ fprintf(stderr,"FATAL BUG: eachPeer() caught NULL peer for %s -- peer pointers in Topology should NEVER be NULL" ZT_EOL_S,a->toString().c_str());
+ abort();
+ }
+#endif
+ f(*this,*((const SharedPtr<Peer> *)p));
+ }
}
/**
- * @return All currently active peers by address
+ * @return All currently active peers by address (unsorted)
*/
inline std::vector< std::pair< Address,SharedPtr<Peer> > > allPeers() const
{
@@ -181,27 +257,23 @@ public:
}
/**
- * Validate a root topology dictionary against the identities specified in Defaults
- *
- * @param rt Root topology dictionary
- * @return True if dictionary signature is valid
+ * @return True if I am a root server in the current World
*/
- static bool authenticateRootTopology(const Dictionary &rt);
+ inline bool amRoot() const throw() { return _amRoot; }
private:
Identity _getIdentity(const Address &zta);
- void _saveIdentity(const Identity &id);
+ void _setWorld(const World &newWorld);
- const RuntimeEnvironment *RR;
+ const RuntimeEnvironment *const RR;
+ World _world;
Hashtable< Address,SharedPtr<Peer> > _peers;
- std::map< Identity,std::vector<InetAddress> > _roots;
std::vector< Address > _rootAddresses;
std::vector< SharedPtr<Peer> > _rootPeers;
+ bool _amRoot;
Mutex _lock;
-
- bool _amRoot;
};
} // namespace ZeroTier
diff --git a/node/Utils.cpp b/node/Utils.cpp
index 658c397d..10146e6c 100644
--- a/node/Utils.cpp
+++ b/node/Utils.cpp
@@ -168,20 +168,20 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
exit(1);
}
- s20.init(s20key,256,s20key,8);
+ s20.init(s20key,256,s20key);
}
if (!CryptGenRandom(cryptProvider,(DWORD)bytes,(BYTE *)buf)) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
exit(1);
}
- s20.encrypt(buf,buf,bytes);
+ s20.encrypt12(buf,buf,bytes);
#else // not __WINDOWS__
#ifdef __UNIX_LIKE__
- static char randomBuf[65536];
+ static char randomBuf[131072];
static unsigned int randomPtr = sizeof(randomBuf);
static int devURandomFd = -1;
static Mutex globalLock;
@@ -191,7 +191,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
if (devURandomFd <= 0) {
devURandomFd = ::open("/dev/urandom",O_RDONLY);
if (devURandomFd <= 0) {
- fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\r\n");
+ fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
exit(1);
return;
}
@@ -199,10 +199,16 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
for(unsigned int i=0;i<bytes;++i) {
if (randomPtr >= sizeof(randomBuf)) {
- if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
- fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to read from /dev/urandom\r\n");
- exit(1);
- return;
+ for(;;) {
+ if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
+ ::close(devURandomFd);
+ devURandomFd = ::open("/dev/urandom",O_RDONLY);
+ if (devURandomFd <= 0) {
+ fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
+ exit(1);
+ return;
+ }
+ } else break;
}
randomPtr = 0;
}
diff --git a/node/World.hpp b/node/World.hpp
new file mode 100644
index 00000000..c6d20d84
--- /dev/null
+++ b/node/World.hpp
@@ -0,0 +1,241 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_WORLD_HPP
+#define ZT_WORLD_HPP
+
+#include <vector>
+#include <string>
+
+#include "Constants.hpp"
+#include "InetAddress.hpp"
+#include "Identity.hpp"
+#include "Buffer.hpp"
+#include "C25519.hpp"
+
+/**
+ * Maximum number of roots (sanity limit, okay to increase)
+ *
+ * A given root can (through multi-homing) be distributed across any number of
+ * physical endpoints, but having more than one is good to permit total failure
+ * of one root or its withdrawal due to compromise without taking the whole net
+ * down.
+ */
+#define ZT_WORLD_MAX_ROOTS 4
+
+/**
+ * Maximum number of stable endpoints per root (sanity limit, okay to increase)
+ */
+#define ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT 32
+
+/**
+ * The (more than) maximum length of a serialized World
+ */
+#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128)
+
+/**
+ * World ID indicating null / empty World object
+ */
+#define ZT_WORLD_ID_NULL 0
+
+/**
+ * World ID for a test network with ephemeral or temporary roots
+ */
+#define ZT_WORLD_ID_TESTNET 1
+
+/**
+ * World ID for Earth
+ *
+ * This is the ID for the ZeroTier World used on planet Earth. It is unrelated
+ * to the public network 8056c2e21c000001 of the same name. It was chosen
+ * from Earth's approximate distance from the sun in kilometers.
+ */
+#define ZT_WORLD_ID_EARTH 149604618
+
+/**
+ * World ID for Mars -- for future use by SpaceX or others
+ */
+#define ZT_WORLD_ID_MARS 227883110
+
+namespace ZeroTier {
+
+/**
+ * A world definition (formerly known as a root topology)
+ *
+ * Think of a World as a single data center. Within this data center a set
+ * of distributed fault tolerant root servers provide stable anchor points
+ * for a peer to peer network that provides VLAN service. Updates to a world
+ * definition can be published by signing them with the previous revision's
+ * signing key, and should be very infrequent.
+ *
+ * The maximum data center size is approximately 2.5 cubic light seconds,
+ * since many protocols have issues with >5s RTT latencies.
+ *
+ * ZeroTier operates a World for Earth capable of encompassing the planet, its
+ * orbits, the Moon (about 1.3 light seconds), and nearby Lagrange points. A
+ * world ID for Mars and nearby space is defined but not yet used, and a test
+ * world ID is provided for testing purposes.
+ *
+ * If you absolutely must run your own "unofficial" ZeroTier network, please
+ * define your world IDs above 0xffffffff (4294967295). Code to make a World
+ * is in mkworld.cpp in the parent directory and must be edited to change
+ * settings.
+ */
+class World
+{
+public:
+ struct Root
+ {
+ Identity identity;
+ std::vector<InetAddress> stableEndpoints;
+
+ inline bool operator==(const Root &r) const throw() { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); }
+ inline bool operator!=(const Root &r) const throw() { return (!(*this == r)); }
+ inline bool operator<(const Root &r) const throw() { return (identity < r.identity); } // for sorting
+ };
+
+ /**
+ * Construct an empty / null World
+ */
+ World() :
+ _id(ZT_WORLD_ID_NULL),
+ _ts(0) {}
+
+ /**
+ * @return Root servers for this world and their stable endpoints
+ */
+ inline const std::vector<World::Root> &roots() const throw() { return _roots; }
+
+ /**
+ * @return World unique identifier
+ */
+ inline uint64_t id() const throw() { return _id; }
+
+ /**
+ * @return World definition timestamp
+ */
+ inline uint64_t timestamp() const throw() { return _ts; }
+
+ /**
+ * Check whether a world update should replace this one
+ *
+ * A new world update is valid if it is for the same world ID, is newer,
+ * and is signed by the current world's signing key. If this world object
+ * is null, it can always be updated.
+ *
+ * @param update Candidate update
+ * @param fullSignatureCheck Perform full cryptographic signature check (true == yes, false == skip)
+ * @return True if update is newer than current and is properly signed
+ */
+ inline bool shouldBeReplacedBy(const World &update,bool fullSignatureCheck)
+ {
+ if (_id == ZT_WORLD_ID_NULL)
+ return true;
+ if ((_id == update._id)&&(_ts < update._ts)) {
+ if (fullSignatureCheck) {
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
+ update.serialize(tmp,true);
+ return C25519::verify(_updateSigningKey,tmp.data(),tmp.size(),update._signature);
+ } else return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return True if this World is non-empty
+ */
+ inline operator bool() const throw() { return (_id != ZT_WORLD_ID_NULL); }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b,bool forSign = false) const
+ {
+ if (forSign)
+ b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
+ b.append((uint8_t)0x01); // version -- only one valid value for now
+ b.append((uint64_t)_id);
+ b.append((uint64_t)_ts);
+ b.append(_updateSigningKey.data,ZT_C25519_PUBLIC_KEY_LEN);
+ if (!forSign)
+ b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
+ b.append((uint8_t)_roots.size());
+ for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
+ r->identity.serialize(b);
+ b.append((uint8_t)r->stableEndpoints.size());
+ for(std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep)
+ ep->serialize(b);
+ }
+ if (forSign)
+ b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL);
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ unsigned int p = startAt;
+
+ _roots.clear();
+
+ if (b[p++] != 0x01)
+ throw std::invalid_argument("invalid World serialized version");
+
+ _id = b.template at<uint64_t>(p); p += 8;
+ _ts = b.template at<uint64_t>(p); p += 8;
+ memcpy(_updateSigningKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN;
+ memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
+ unsigned int numRoots = b[p++];
+ if (numRoots > ZT_WORLD_MAX_ROOTS)
+ throw std::invalid_argument("too many roots in World");
+ for(unsigned int k=0;k<numRoots;++k) {
+ _roots.push_back(Root());
+ Root &r = _roots.back();
+ p += r.identity.deserialize(b,p);
+ unsigned int numStableEndpoints = b[p++];
+ if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)
+ throw std::invalid_argument("too many stable endpoints in World/Root");
+ for(unsigned int kk=0;kk<numStableEndpoints;++kk) {
+ r.stableEndpoints.push_back(InetAddress());
+ p += r.stableEndpoints.back().deserialize(b,p);
+ }
+ }
+
+ return (p - startAt);
+ }
+
+ inline bool operator==(const World &w) const throw() { return ((_id == w._id)&&(_ts == w._ts)&&(_updateSigningKey == w._updateSigningKey)&&(_signature == w._signature)&&(_roots == w._roots)); }
+ inline bool operator!=(const World &w) const throw() { return (!(*this == w)); }
+
+protected:
+ uint64_t _id;
+ uint64_t _ts;
+ C25519::Public _updateSigningKey;
+ C25519::Signature _signature;
+ std::vector<Root> _roots;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/objects.mk b/objects.mk
index 0986ef0d..8daec8b5 100644
--- a/objects.mk
+++ b/objects.mk
@@ -4,7 +4,8 @@ OBJS=\
ext/http-parser/http_parser.o \
node/C25519.o \
node/CertificateOfMembership.o \
- node/Defaults.o \
+ node/Cluster.o \
+ node/DeferredPackets.o \
node/Dictionary.o \
node/Identity.o \
node/IncomingPacket.o \
@@ -15,6 +16,7 @@ OBJS=\
node/Node.o \
node/OutboundMulticast.o \
node/Packet.o \
+ node/Path.o \
node/Peer.o \
node/Poly1305.o \
node/Salsa20.o \
@@ -26,5 +28,6 @@ OBJS=\
osdep/BackgroundResolver.o \
osdep/Http.o \
osdep/OSUtils.o \
+ service/ClusterGeoIpService.o \
service/ControlPlane.o \
service/OneService.o
diff --git a/one.cpp b/one.cpp
index a4d5190c..685034df 100644
--- a/one.cpp
+++ b/one.cpp
@@ -911,7 +911,6 @@ static void printHelp(const char *cn,FILE *out)
fprintf(out," -v - Show version"ZT_EOL_S);
fprintf(out," -U - Run as unprivileged user (skip privilege check)"ZT_EOL_S);
fprintf(out," -p<port> - Port for UDP and TCP/HTTP (default: 9993, 0 for random)"ZT_EOL_S);
- //fprintf(out," -T<path> - Override root topology, do not authenticate or update"ZT_EOL_S);
#ifdef __UNIX_LIKE__
fprintf(out," -d - Fork and run as daemon (Unix-ish OSes)"ZT_EOL_S);
@@ -959,8 +958,10 @@ int main(int argc,char **argv)
#endif // __UNIX_LIKE__
#ifdef __WINDOWS__
- WSADATA wsaData;
- WSAStartup(MAKEWORD(2,2),&wsaData);
+ {
+ WSADATA wsaData;
+ WSAStartup(MAKEWORD(2,2),&wsaData);
+ }
#ifdef ZT_WIN_RUN_IN_CONSOLE
bool winRunFromCommandLine = true;
@@ -974,7 +975,6 @@ int main(int argc,char **argv)
if ((strstr(argv[0],"zerotier-cli"))||(strstr(argv[0],"ZEROTIER-CLI")))
return cli(argc,argv);
- std::string overrideRootTopology;
std::string homeDir;
unsigned int port = ZT_DEFAULT_PORT;
bool skipRootCheck = false;
@@ -1001,18 +1001,6 @@ int main(int argc,char **argv)
skipRootCheck = true;
break;
- case 'T': // Override root topology
- if (argv[i][2]) {
- if (!OSUtils::readFile(argv[i] + 2,overrideRootTopology)) {
- fprintf(stderr,"%s: cannot read root topology from %s"ZT_EOL_S,argv[0],argv[i] + 2);
- return 1;
- }
- } else {
- printHelp(argv[0],stdout);
- return 1;
- }
- break;
-
case 'v': // Display version
printf("%d.%d.%d"ZT_EOL_S,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION);
return 0;
@@ -1167,37 +1155,29 @@ int main(int argc,char **argv)
unsigned int returnValue = 0;
- try {
- for(;;) {
- zt1Service = OneService::newInstance(homeDir.c_str(),port,(overrideRootTopology.length() > 0) ? overrideRootTopology.c_str() : (const char *)0);
- switch(zt1Service->run()) {
- case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done
- case OneService::ONE_NORMAL_TERMINATION:
- break;
- case OneService::ONE_UNRECOVERABLE_ERROR:
- fprintf(stderr,"%s: fatal error: %s"ZT_EOL_S,argv[0],zt1Service->fatalErrorMessage().c_str());
- returnValue = 1;
- break;
- case OneService::ONE_IDENTITY_COLLISION: {
- delete zt1Service;
- zt1Service = (OneService *)0;
- std::string oldid;
- OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid);
- if (oldid.length()) {
- OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid);
- OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
- OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
- }
- } continue; // restart!
- }
- break; // terminate loop -- normally we don't keep restarting
+ for(;;) {
+ zt1Service = OneService::newInstance(homeDir.c_str(),port);
+ switch(zt1Service->run()) {
+ case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done
+ case OneService::ONE_NORMAL_TERMINATION:
+ break;
+ case OneService::ONE_UNRECOVERABLE_ERROR:
+ fprintf(stderr,"%s: fatal error: %s"ZT_EOL_S,argv[0],zt1Service->fatalErrorMessage().c_str());
+ returnValue = 1;
+ break;
+ case OneService::ONE_IDENTITY_COLLISION: {
+ delete zt1Service;
+ zt1Service = (OneService *)0;
+ std::string oldid;
+ OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid);
+ if (oldid.length()) {
+ OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid);
+ OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
+ OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
+ }
+ } continue; // restart!
}
- } catch (std::exception &exc) {
- fprintf(stderr,"%s: fatal error: %s"ZT_EOL_S,argv[0],exc.what());
- returnValue = 1;
- } catch ( ... ) {
- fprintf(stderr,"%s: fatal error: unknown exception"ZT_EOL_S,argv[0]);
- returnValue = 1;
+ break; // terminate loop -- normally we don't keep restarting
}
delete zt1Service;
diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp
index 2ca00f0d..d1023b4d 100644
--- a/osdep/Arp.cpp
+++ b/osdep/Arp.cpp
@@ -104,11 +104,11 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
return ip;
}
-MAC Arp::query(const MAC &localMac,uint32_t ip,void *query,unsigned int &queryLen,MAC &queryDest)
+MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest)
{
const uint64_t now = OSUtils::now();
- _ArpEntry &e = _cache[ip];
+ _ArpEntry &e = _cache[targetIp];
if ( ((e.mac)&&((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) ||
((!e.mac)&&((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL)) ) {
@@ -116,9 +116,10 @@ MAC Arp::query(const MAC &localMac,uint32_t ip,void *query,unsigned int &queryLe
uint8_t *q = reinterpret_cast<uint8_t *>(query);
memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same
- localMac.copyTo(q,6); q += 6; // sending host address
- memset(q,0,10); q += 10; // sending IP and target media address are ignored in requests
- memcpy(q,&ip,4); // target IP address for resolution (IP already in big-endian byte order)
+ localMac.copyTo(q,6); q += 6; // sending host MAC address
+ memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order)
+ memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find
+ memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order)
queryLen = 28;
if (e.mac)
queryDest = e.mac; // confirmation query, send directly to address holder
diff --git a/osdep/Arp.hpp b/osdep/Arp.hpp
index b747cf85..129935cf 100644
--- a/osdep/Arp.hpp
+++ b/osdep/Arp.hpp
@@ -129,13 +129,14 @@ public:
* MAC returned is non-null.
*
* @param localMac Local MAC address of host interface
- * @param ip IP to look up
+ * @param localIp Local IP address of host interface
+ * @param targetIp IP to look up
* @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size
* @param queryLen Length of generated query, or set to 0 if no query generated
* @param queryDest Destination of query, or set to null if no query generated
* @return MAC or 0 if no cached entry for this IP
*/
- MAC query(const MAC &localMac,uint32_t ip,void *query,unsigned int &queryLen,MAC &queryDest);
+ MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest);
private:
struct _ArpEntry
diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp
index 45fbf100..728704e5 100644
--- a/osdep/OSUtils.cpp
+++ b/osdep/OSUtils.cpp
@@ -206,7 +206,7 @@ skip_add_inetaddr:
bool OSUtils::readFile(const char *path,std::string &buf)
{
- char tmp[4096];
+ char tmp[1024];
FILE *f = fopen(path,"rb");
if (f) {
for(;;) {
diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp
index 5de35eba..43fd2813 100644
--- a/osdep/OSUtils.hpp
+++ b/osdep/OSUtils.hpp
@@ -95,7 +95,6 @@ public:
static inline bool rm(const std::string &path) throw() { return rm(path.c_str()); }
static inline bool mkdir(const char *path)
- throw()
{
#ifdef __WINDOWS__
if (::PathIsDirectoryA(path))
diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp
index c7b2a340..84d154a3 100644
--- a/osdep/Phy.hpp
+++ b/osdep/Phy.hpp
@@ -64,6 +64,12 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
+#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
+#ifndef IPV6_DONTFRAG
+#define IPV6_DONTFRAG 62
+#endif
+#endif
+
#define ZT_PHY_SOCKFD_TYPE int
#define ZT_PHY_SOCKFD_NULL (-1)
#define ZT_PHY_SOCKFD_VALID(s) ((s) > -1)
@@ -365,6 +371,9 @@ public:
#ifdef IPV6_MTU_DISCOVER
f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f));
#endif
+#ifdef IPV6_DONTFRAG
+ f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,&f,sizeof(f));
+#endif
}
f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f));
@@ -414,6 +423,24 @@ public:
}
/**
+ * Set the IP TTL for the next outgoing packet (for IPv4 UDP sockets only)
+ *
+ * @param ttl New TTL (0 or >255 will set it to 255)
+ * @return True on success
+ */
+ inline bool setIp4UdpTtl(PhySocket *sock,unsigned int ttl)
+ {
+ PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
+#if defined(_WIN32) || defined(_WIN64)
+ DWORD tmp = ((ttl == 0)||(ttl > 255)) ? 255 : (DWORD)ttl;
+ return (::setsockopt(sws.sock,IPPROTO_IP,IP_TTL,(const char *)&tmp,sizeof(tmp)) == 0);
+#else
+ int tmp = ((ttl == 0)||(ttl > 255)) ? 255 : (int)ttl;
+ return (::setsockopt(sws.sock,IPPROTO_IP,IP_TTL,(void *)&tmp,sizeof(tmp)) == 0);
+#endif
+ }
+
+ /**
* Send a UDP packet
*
* @param sock UDP socket
@@ -655,6 +682,36 @@ public:
}
/**
+ * Try to set buffer sizes as close to the given value as possible
+ *
+ * This will try the specified value and then lower values in 16K increments
+ * until one works.
+ *
+ * @param sock Socket
+ * @param bufferSize Desired buffer sizes
+ */
+ inline void setBufferSizes(const PhySocket *sock,int bufferSize)
+ {
+ PhySocketImpl &sws = *(reinterpret_cast<PhySocketImpl *>(sock));
+ if (bufferSize > 0) {
+ int bs = bufferSize;
+ while (bs >= 65536) {
+ int tmpbs = bs;
+ if (::setsockopt(sws.sock,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
+ break;
+ bs -= 16384;
+ }
+ bs = bufferSize;
+ while (bs >= 65536) {
+ int tmpbs = bs;
+ if (::setsockopt(sws.sock,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
+ break;
+ bs -= 16384;
+ }
+ }
+ }
+
+ /**
* Attempt to send data to a stream socket (non-blocking)
*
* If -1 is returned, the socket should no longer be used as it is now
diff --git a/osdep/UPNPClient.cpp b/osdep/UPNPClient.cpp
index ceecb3a3..b7c7e768 100644
--- a/osdep/UPNPClient.cpp
+++ b/osdep/UPNPClient.cpp
@@ -46,8 +46,8 @@
#endif
#endif
-#include "../ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h"
-#include "../ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h"
+#include "../ext/miniupnpc/miniupnpc.h"
+#include "../ext/miniupnpc/upnpcommands.h"
namespace ZeroTier {
@@ -81,7 +81,7 @@ public:
while (run) {
{
int upnpError = 0;
- UPNPDev *devlist = upnpDiscover(2000,(const char *)0,(const char *)0,0,0,&upnpError);
+ UPNPDev *devlist = upnpDiscover(2000,(const char *)0,(const char *)0,0,0,0,&upnpError);
if (devlist) {
#ifdef ZT_UPNP_TRACE
{
@@ -115,7 +115,7 @@ public:
Utils::snprintf(outport,sizeof(outport),"%u",tryPort);
int mapResult = 0;
- if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,"ZeroTier","UDP",(const char *)0,ZT_UPNP_LEASE_DURATION)) == UPNPCOMMAND_SUCCESS) {
+ if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,"ZeroTier","UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) {
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: reserved external port: %s"ZT_EOL_S,outport);
#endif
diff --git a/osdep/UPNPClient.hpp b/osdep/UPNPClient.hpp
index 28b9979d..a6b05b5f 100644
--- a/osdep/UPNPClient.hpp
+++ b/osdep/UPNPClient.hpp
@@ -42,11 +42,6 @@
*/
#define ZT_UPNP_CLIENT_REFRESH_DELAY 600000
-/**
- * UPNP lease duration in seconds (as string)
- */
-#define ZT_UPNP_LEASE_DURATION "3600"
-
namespace ZeroTier {
class UPNPClientImpl;
diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp
index f327009d..5b2bc154 100644
--- a/osdep/WindowsEthernetTap.cpp
+++ b/osdep/WindowsEthernetTap.cpp
@@ -213,7 +213,7 @@ std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf,
Mutex::Lock _l(_systemDeviceManagementLock);
GUID classGuid;
- char className[4096];
+ char className[1024];
if (!WINENV.SetupDiGetINFClassA(pathToInf,&classGuid,className,sizeof(className),(PDWORD)0)) {
return std::string("SetupDiGetINFClassA() failed -- unable to read zttap driver INF file");
}
@@ -269,9 +269,9 @@ std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf,
std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices()
{
- char subkeyName[4096];
- char subkeyClass[4096];
- char data[4096];
+ char subkeyName[1024];
+ char subkeyClass[1024];
+ char data[1024];
std::set<std::string> instanceIdPathsToRemove;
{
@@ -321,9 +321,9 @@ std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices()
std::string WindowsEthernetTap::destroyAllPersistentTapDevices()
{
- char subkeyName[4096];
- char subkeyClass[4096];
- char data[4096];
+ char subkeyName[1024];
+ char subkeyClass[1024];
+ char data[1024];
std::set<std::string> instanceIdPathsToRemove;
{
@@ -479,9 +479,9 @@ WindowsEthernetTap::WindowsEthernetTap(
_initialized(false),
_enabled(true)
{
- char subkeyName[4096];
- char subkeyClass[4096];
- char data[4096];
+ char subkeyName[1024];
+ char subkeyClass[1024];
+ char data[1024];
char tag[24];
std::string mySubkeyName;
diff --git a/root-topology/Makefile b/root-topology/Makefile
deleted file mode 100644
index 3ddd916f..00000000
--- a/root-topology/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-all: FORCE
- g++ -o mktopology mktopology.cpp ../osdep/OSUtils.cpp ../node/Utils.cpp ../node/InetAddress.cpp ../node/Identity.cpp ../node/C25519.cpp ../node/Salsa20.cpp ../node/Dictionary.cpp ../node/SHA512.cpp
- gcc -o bin2c bin2c.c
-
-official: FORCE
- rm -f ZT_DEFAULT_ROOT_TOPOLOGY.dict
- ./mktopology >ZT_DEFAULT_ROOT_TOPOLOGY.dict
- ./bin2c ZT_DEFAULT_ROOT_TOPOLOGY < ZT_DEFAULT_ROOT_TOPOLOGY.dict > ZT_DEFAULT_ROOT_TOPOLOGY.c
- ls -l ZT_DEFAULT_ROOT_TOPOLOGY.c
-
-clean:
- rm -f *.o mktopology bin2c
-
-realclean: clean
- rm -f ZT_DEFAULT_ROOT_TOPOLOGY.c ZT_DEFAULT_ROOT_TOPOLOGY.dict
-
-FORCE:
diff --git a/root-topology/README.md b/root-topology/README.md
deleted file mode 100644
index c9c3a908..00000000
--- a/root-topology/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-This folder contains the source files to compile the signed network root topology dictionary. Users outside ZeroTier won't find this useful except for testing, since the root topology must be signed by the root topology authority (public identity in root-topology-authority.public) to be considered valid.
-
-Keys in the root topology dictionary are:
-
- * **rootservers**: contains another Dictionary mapping rootserver address to rootserver definition
- * **##########**: rootserver address, contains rootserver definition
- * **id**: rootserver identity (public) in string-serialized format
- * **udp**: comma-delimited list of ip/port UDP addresses of node
- * **tcp**: *DEPRECATED* comma-delimited list of ip/port TCP addresses of node
- * **desc**: human-readable description (optional)
- * **dns**: DNS name (optional, not currently used for anything)
- * **noupdate**: if the value of this is '1', do not auto-update from ZeroTier's servers
-
-ZT_DEFAULT_ROOT_TOPOLOGY.c contains the current default value, and this URL is periodically checked for updates:
-
-http://download.zerotier.com/net/topology/ROOT
-
-Obviously nothing prevents OSS users from replacing this topology with their own, changing the hard coded topology signing identity and update URL in Defaults, and signing their own dictionary. But doing so would yield a network that would have a tough(ish) time talking to the main one. Since the main network is a free service, why bother? (Except for building testnets, which ZeroTier already does for internal testing.)
diff --git a/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c b/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c
deleted file mode 100644
index 96835e05..00000000
--- a/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c
+++ /dev/null
@@ -1,90 +0,0 @@
-static unsigned char ZT_DEFAULT_ROOT_TOPOLOGY[] = {
- 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x3d, 0x37, 0x65, 0x31, 0x39,
- 0x38, 0x37, 0x36, 0x61, 0x62, 0x61, 0x5c, 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x37, 0x65,
- 0x31, 0x39, 0x38, 0x37, 0x36, 0x61, 0x62, 0x61, 0x3a, 0x30, 0x3a, 0x32, 0x61, 0x36, 0x65, 0x32,
- 0x62, 0x32, 0x33, 0x31, 0x38, 0x39, 0x33, 0x30, 0x66, 0x36, 0x30, 0x65, 0x62, 0x30, 0x39, 0x37,
- 0x66, 0x37, 0x30, 0x64, 0x30, 0x66, 0x34, 0x62, 0x30, 0x32, 0x38, 0x62, 0x32, 0x63, 0x64, 0x36,
- 0x64, 0x33, 0x64, 0x30, 0x63, 0x36, 0x33, 0x63, 0x30, 0x31, 0x34, 0x62, 0x39, 0x30, 0x33, 0x39,
- 0x66, 0x66, 0x33, 0x35, 0x33, 0x39, 0x30, 0x65, 0x34, 0x31, 0x31, 0x38, 0x31, 0x66, 0x32, 0x31,
- 0x36, 0x66, 0x62, 0x32, 0x65, 0x36, 0x66, 0x61, 0x38, 0x64, 0x39, 0x35, 0x63, 0x31, 0x65, 0x65,
- 0x39, 0x36, 0x36, 0x37, 0x31, 0x35, 0x36, 0x34, 0x31, 0x31, 0x39, 0x30, 0x35, 0x63, 0x33, 0x64,
- 0x63, 0x63, 0x66, 0x65, 0x61, 0x37, 0x38, 0x64, 0x38, 0x63, 0x36, 0x64, 0x66, 0x61, 0x66, 0x62,
- 0x61, 0x36, 0x38, 0x38, 0x31, 0x37, 0x30, 0x62, 0x33, 0x66, 0x61, 0x5c, 0x5c, 0x6e, 0x75, 0x64,
- 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x39, 0x37, 0x2e,
- 0x32, 0x32, 0x30, 0x2f, 0x39, 0x39, 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c,
- 0x5c, 0x3d, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x39, 0x37, 0x2e, 0x32, 0x32, 0x30,
- 0x2f, 0x34, 0x34, 0x33, 0x5c, 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x53,
- 0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2c, 0x20, 0x43, 0x61,
- 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x2c, 0x20, 0x55, 0x53, 0x41, 0x5c, 0x5c, 0x6e,
- 0x5c, 0x6e, 0x38, 0x38, 0x34, 0x31, 0x34, 0x30, 0x38, 0x61, 0x32, 0x65, 0x5c, 0x3d, 0x69, 0x64,
- 0x5c, 0x5c, 0x5c, 0x3d, 0x38, 0x38, 0x34, 0x31, 0x34, 0x30, 0x38, 0x61, 0x32, 0x65, 0x3a, 0x30,
- 0x3a, 0x62, 0x62, 0x31, 0x64, 0x33, 0x31, 0x66, 0x32, 0x63, 0x33, 0x32, 0x33, 0x65, 0x32, 0x36,
- 0x34, 0x65, 0x39, 0x65, 0x36, 0x34, 0x31, 0x37, 0x32, 0x63, 0x31, 0x61, 0x37, 0x34, 0x66, 0x37,
- 0x37, 0x38, 0x39, 0x39, 0x35, 0x35, 0x35, 0x65, 0x64, 0x31, 0x30, 0x37, 0x35, 0x31, 0x63, 0x64,
- 0x35, 0x36, 0x65, 0x38, 0x36, 0x34, 0x30, 0x35, 0x63, 0x64, 0x65, 0x31, 0x31, 0x38, 0x64, 0x30,
- 0x32, 0x64, 0x66, 0x66, 0x65, 0x35, 0x35, 0x35, 0x64, 0x34, 0x36, 0x32, 0x63, 0x63, 0x66, 0x36,
- 0x61, 0x38, 0x35, 0x62, 0x35, 0x36, 0x33, 0x31, 0x63, 0x31, 0x32, 0x33, 0x35, 0x30, 0x63, 0x38,
- 0x64, 0x35, 0x64, 0x63, 0x34, 0x30, 0x39, 0x62, 0x61, 0x31, 0x30, 0x62, 0x39, 0x30, 0x32, 0x35,
- 0x64, 0x30, 0x66, 0x34, 0x34, 0x35, 0x63, 0x66, 0x34, 0x34, 0x39, 0x64, 0x39, 0x32, 0x62, 0x31,
- 0x63, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x30, 0x37, 0x2e, 0x31,
- 0x39, 0x31, 0x2e, 0x34, 0x36, 0x2e, 0x32, 0x31, 0x30, 0x2f, 0x39, 0x39, 0x39, 0x33, 0x5c, 0x5c,
- 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x30, 0x37, 0x2e, 0x31, 0x39, 0x31, 0x2e,
- 0x34, 0x36, 0x2e, 0x32, 0x31, 0x30, 0x2f, 0x34, 0x34, 0x33, 0x5c, 0x5c, 0x6e, 0x64, 0x65, 0x73,
- 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x50, 0x61, 0x72, 0x69, 0x73, 0x2c, 0x20, 0x46, 0x72, 0x61, 0x6e,
- 0x63, 0x65, 0x5c, 0x5c, 0x6e, 0x5c, 0x6e, 0x38, 0x61, 0x63, 0x66, 0x30, 0x35, 0x39, 0x66, 0x65,
- 0x33, 0x5c, 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x38, 0x61, 0x63, 0x66, 0x30, 0x35, 0x39,
- 0x66, 0x65, 0x33, 0x3a, 0x30, 0x3a, 0x34, 0x38, 0x32, 0x66, 0x36, 0x65, 0x65, 0x35, 0x64, 0x66,
- 0x65, 0x39, 0x30, 0x32, 0x33, 0x31, 0x39, 0x62, 0x34, 0x31, 0x39, 0x64, 0x65, 0x35, 0x62, 0x64,
- 0x63, 0x37, 0x36, 0x35, 0x32, 0x30, 0x39, 0x63, 0x30, 0x65, 0x63, 0x64, 0x61, 0x33, 0x38, 0x63,
- 0x34, 0x64, 0x36, 0x65, 0x34, 0x66, 0x63, 0x66, 0x30, 0x64, 0x33, 0x33, 0x36, 0x35, 0x38, 0x33,
- 0x39, 0x38, 0x62, 0x34, 0x35, 0x32, 0x37, 0x64, 0x63, 0x64, 0x32, 0x32, 0x66, 0x39, 0x33, 0x31,
- 0x31, 0x32, 0x66, 0x62, 0x39, 0x62, 0x65, 0x66, 0x64, 0x30, 0x32, 0x66, 0x64, 0x37, 0x38, 0x62,
- 0x66, 0x37, 0x32, 0x36, 0x31, 0x62, 0x33, 0x33, 0x33, 0x66, 0x63, 0x31, 0x30, 0x35, 0x64, 0x31,
- 0x39, 0x32, 0x61, 0x36, 0x32, 0x33, 0x63, 0x61, 0x39, 0x65, 0x35, 0x30, 0x66, 0x63, 0x36, 0x30,
- 0x62, 0x33, 0x37, 0x34, 0x61, 0x35, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c, 0x3d,
- 0x31, 0x36, 0x32, 0x2e, 0x32, 0x34, 0x33, 0x2e, 0x37, 0x37, 0x2e, 0x31, 0x31, 0x31, 0x2f, 0x39,
- 0x39, 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x36, 0x32,
- 0x2e, 0x32, 0x34, 0x33, 0x2e, 0x37, 0x37, 0x2e, 0x31, 0x31, 0x31, 0x2f, 0x34, 0x34, 0x33, 0x5c,
- 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x4e, 0x65, 0x77, 0x20, 0x59, 0x6f,
- 0x72, 0x6b, 0x2c, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x2c, 0x20, 0x55, 0x53,
- 0x41, 0x5c, 0x5c, 0x6e, 0x5c, 0x6e, 0x39, 0x64, 0x32, 0x31, 0x39, 0x30, 0x33, 0x39, 0x66, 0x33,
- 0x5c, 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x39, 0x64, 0x32, 0x31, 0x39, 0x30, 0x33, 0x39,
- 0x66, 0x33, 0x3a, 0x30, 0x3a, 0x30, 0x31, 0x66, 0x30, 0x39, 0x32, 0x32, 0x61, 0x39, 0x38, 0x65,
- 0x33, 0x62, 0x33, 0x34, 0x65, 0x62, 0x63, 0x62, 0x66, 0x66, 0x33, 0x33, 0x33, 0x32, 0x36, 0x39,
- 0x64, 0x63, 0x32, 0x36, 0x35, 0x64, 0x37, 0x61, 0x30, 0x32, 0x30, 0x61, 0x61, 0x62, 0x36, 0x39,
- 0x64, 0x37, 0x32, 0x62, 0x65, 0x34, 0x64, 0x34, 0x61, 0x63, 0x63, 0x39, 0x63, 0x38, 0x63, 0x39,
- 0x32, 0x39, 0x34, 0x37, 0x38, 0x35, 0x37, 0x37, 0x31, 0x32, 0x35, 0x36, 0x63, 0x64, 0x31, 0x64,
- 0x39, 0x34, 0x32, 0x61, 0x39, 0x30, 0x64, 0x31, 0x62, 0x64, 0x31, 0x64, 0x32, 0x64, 0x63, 0x61,
- 0x33, 0x65, 0x61, 0x38, 0x34, 0x65, 0x66, 0x37, 0x64, 0x38, 0x35, 0x61, 0x66, 0x65, 0x36, 0x36,
- 0x31, 0x31, 0x66, 0x62, 0x34, 0x33, 0x66, 0x66, 0x30, 0x62, 0x37, 0x34, 0x31, 0x32, 0x36, 0x64,
- 0x39, 0x30, 0x61, 0x36, 0x65, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31,
- 0x32, 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x31, 0x39, 0x37, 0x2e, 0x32, 0x31, 0x37, 0x2f, 0x39,
- 0x39, 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x32, 0x38,
- 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x31, 0x39, 0x37, 0x2e, 0x32, 0x31, 0x37, 0x2f, 0x34, 0x34, 0x33,
- 0x5c, 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x53, 0x69, 0x6e, 0x67, 0x61,
- 0x70, 0x6f, 0x72, 0x65, 0x5c, 0x5c, 0x6e, 0x5c, 0x6e, 0x0a, 0x7e, 0x21, 0x65, 0x64, 0x32, 0x35,
- 0x35, 0x31, 0x39, 0x3d, 0x38, 0x33, 0x32, 0x62, 0x33, 0x35, 0x64, 0x61, 0x64, 0x64, 0x37, 0x66,
- 0x35, 0x36, 0x66, 0x66, 0x33, 0x38, 0x31, 0x66, 0x61, 0x37, 0x32, 0x31, 0x64, 0x65, 0x37, 0x64,
- 0x35, 0x62, 0x65, 0x34, 0x63, 0x65, 0x62, 0x66, 0x63, 0x63, 0x63, 0x32, 0x30, 0x30, 0x32, 0x30,
- 0x38, 0x33, 0x38, 0x30, 0x64, 0x33, 0x30, 0x38, 0x34, 0x66, 0x36, 0x34, 0x38, 0x65, 0x32, 0x63,
- 0x31, 0x61, 0x35, 0x63, 0x66, 0x34, 0x33, 0x65, 0x35, 0x39, 0x66, 0x39, 0x32, 0x61, 0x36, 0x36,
- 0x35, 0x64, 0x66, 0x34, 0x64, 0x62, 0x63, 0x62, 0x38, 0x33, 0x37, 0x38, 0x38, 0x66, 0x36, 0x62,
- 0x64, 0x36, 0x37, 0x37, 0x66, 0x30, 0x32, 0x62, 0x32, 0x31, 0x30, 0x65, 0x35, 0x30, 0x63, 0x61,
- 0x66, 0x65, 0x66, 0x64, 0x32, 0x65, 0x66, 0x31, 0x38, 0x39, 0x62, 0x62, 0x66, 0x34, 0x38, 0x31,
- 0x62, 0x64, 0x30, 0x32, 0x63, 0x64, 0x63, 0x39, 0x38, 0x34, 0x35, 0x33, 0x38, 0x37, 0x64, 0x38,
- 0x34, 0x39, 0x62, 0x63, 0x35, 0x36, 0x66, 0x39, 0x63, 0x37, 0x32, 0x35, 0x31, 0x65, 0x35, 0x64,
- 0x30, 0x65, 0x61, 0x34, 0x34, 0x34, 0x66, 0x66, 0x63, 0x66, 0x38, 0x66, 0x37, 0x32, 0x32, 0x63,
- 0x32, 0x66, 0x65, 0x62, 0x38, 0x39, 0x36, 0x30, 0x33, 0x61, 0x30, 0x65, 0x35, 0x62, 0x61, 0x32,
- 0x39, 0x35, 0x66, 0x63, 0x0a, 0x7e, 0x21, 0x73, 0x69, 0x67, 0x69, 0x64, 0x3d, 0x37, 0x37, 0x37,
- 0x39, 0x32, 0x62, 0x31, 0x63, 0x30, 0x32, 0x3a, 0x30, 0x3a, 0x62, 0x35, 0x63, 0x33, 0x36, 0x31,
- 0x65, 0x38, 0x65, 0x39, 0x63, 0x32, 0x31, 0x35, 0x34, 0x65, 0x38, 0x32, 0x63, 0x33, 0x65, 0x39,
- 0x30, 0x32, 0x66, 0x64, 0x66, 0x63, 0x33, 0x33, 0x37, 0x34, 0x36, 0x38, 0x62, 0x30, 0x39, 0x32,
- 0x61, 0x37, 0x63, 0x34, 0x64, 0x38, 0x64, 0x63, 0x36, 0x38, 0x35, 0x63, 0x33, 0x37, 0x65, 0x62,
- 0x31, 0x30, 0x65, 0x65, 0x34, 0x66, 0x33, 0x63, 0x31, 0x37, 0x63, 0x63, 0x30, 0x62, 0x62, 0x31,
- 0x64, 0x30, 0x32, 0x34, 0x31, 0x36, 0x37, 0x65, 0x38, 0x63, 0x62, 0x30, 0x38, 0x32, 0x34, 0x64,
- 0x31, 0x32, 0x32, 0x36, 0x33, 0x34, 0x32, 0x38, 0x33, 0x37, 0x33, 0x35, 0x38, 0x32, 0x64, 0x61,
- 0x33, 0x64, 0x30, 0x61, 0x39, 0x61, 0x31, 0x34, 0x62, 0x33, 0x36, 0x65, 0x34, 0x35, 0x34, 0x36,
- 0x63, 0x33, 0x31, 0x37, 0x65, 0x38, 0x31, 0x31, 0x65, 0x36, 0x0a, 0x7e, 0x21, 0x73, 0x69, 0x67,
- 0x74, 0x73, 0x3d, 0x31, 0x34, 0x65, 0x30, 0x63, 0x62, 0x62, 0x39, 0x38, 0x64, 0x36, 0x0a
-};
-#define ZT_DEFAULT_ROOT_TOPOLOGY_LEN 1391
diff --git a/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict b/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict
deleted file mode 100644
index 58144758..00000000
--- a/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict
+++ /dev/null
@@ -1,4 +0,0 @@
-rootservers=7e19876aba\=id\\\=7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa\\nudp\\\=198.199.97.220/9993\\ntcp\\\=198.199.97.220/443\\ndesc\\\=San Francisco, California, USA\\n\n8841408a2e\=id\\\=8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c\\nudp\\\=107.191.46.210/9993\\ntcp\\\=107.191.46.210/443\\ndesc\\\=Paris, France\\n\n8acf059fe3\=id\\\=8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5\\nudp\\\=162.243.77.111/9993\\ntcp\\\=162.243.77.111/443\\ndesc\\\=New York, New York, USA\\n\n9d219039f3\=id\\\=9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e\\nudp\\\=128.199.197.217/9993\\ntcp\\\=128.199.197.217/443\\ndesc\\\=Singapore\\n\n
-~!ed25519=832b35dadd7f56ff381fa721de7d5be4cebfccc200208380d3084f648e2c1a5cf43e59f92a665df4dbcb83788f6bd677f02b210e50cafefd2ef189bbf481bd02cdc9845387d849bc56f9c7251e5d0ea444ffcf8f722c2feb89603a0e5ba295fc
-~!sigid=77792b1c02:0:b5c361e8e9c2154e82c3e902fdfc337468b092a7c4d8dc685c37eb10ee4f3c17cc0bb1d024167e8cb0824d12263428373582da3d0a9a14b36e4546c317e811e6
-~!sigts=14e0cbb98d6
diff --git a/root-topology/bin2c.c b/root-topology/bin2c.c
deleted file mode 100644
index a30deee5..00000000
--- a/root-topology/bin2c.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- Converts input from stdin into an array of binary data for use in C.
-
- License: Public Domain
-
- Usage: app VariableName < input > output.c
-*/
-
-#include <stdint.h> /* uintXX_t */
-#include <inttypes.h> /* PRIuXX macros */
-#include <stdio.h>
-
-static char const * appName = 0;
-
-static void usage()
-{
- printf("Usage: %s OBJECT_NAME < input > output.c\n\n", appName );
-}
-
-int main( int argc, char const ** argv )
-{
- appName = argv[0];
- if( (argc != 2) || (argv[1][0] == '-') )
- {
- usage();
- return 1;
- }
- char const * varname = argv[1];
- enum { bufSize = 1024 * 8 };
- unsigned char buf[bufSize];
- size_t rd = 0;
- size_t i = 0;
- size_t flip = 0;
-
- printf( "static unsigned char %s[] = {\n\t", varname);
- uint32_t size = 0;
- while( 0 != (rd = fread( buf, 1, bufSize, stdin ) ) )
- {
- size += rd;
- for(i = 0; i < rd; ++i )
- {
- printf( "0x%02x", buf[i] );
- if( !( (rd < bufSize) && (i == rd-1)) ) putchar(',');
- if( 16 == ++flip )
- {
- flip = 0;
- printf("\n\t");
- }
- else putchar(' ');
- }
- }
- printf("\n};\n");
- printf("#define %s_LEN %llu\n",varname,(unsigned long long)size);
- //printf( "enum { %s_length = %"PRIu32"%s }; ", varname, size,"UL");
- //printf("enum { %s_length = sizeof(%s) };\n", varname, varname );
- return 0;
-}
diff --git a/root-topology/mktopology.cpp b/root-topology/mktopology.cpp
deleted file mode 100644
index f0ad5b55..00000000
--- a/root-topology/mktopology.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <string>
-#include <iostream>
-#include <map>
-
-#include "../osdep/OSUtils.hpp"
-#include "../node/Identity.hpp"
-#include "../node/Dictionary.hpp"
-
-using namespace ZeroTier;
-
-int main(int argc,char **argv)
-{
- std::string buf;
-
- // Read root-topology-authority.secret signing authority, must be symlinked and online
- Identity topologyAuthority;
- if (OSUtils::readFile("root-topology-authority.secret",buf))
- topologyAuthority.fromString(buf);
- else std::cerr << "Warning: root-topology-authority.secret not found, creating unsigned topology." << std::endl;
-
- Dictionary topology;
-
- // Read template.dict to populate default fields in root topology
- // if this file exists. Otherwise we just start empty.
- buf.clear();
- if (OSUtils::readFile("template.dict",buf))
- topology.fromString(buf);
-
- // Read all entries in rootservers/ that correspond to rootserver entry dictionaries
- // and add them to topology under rootservers/ subkey.
- Dictionary rootservers;
- std::vector<std::string> rootserverDictionaries(OSUtils::listDirectory("rootservers"));
- for(std::vector<std::string>::const_iterator sn(rootserverDictionaries.begin());sn!=rootserverDictionaries.end();++sn) {
- if (sn->length() == 10) {
- buf.clear();
- if (!OSUtils::readFile((std::string("rootservers/")+(*sn)).c_str(),buf)) {
- std::cerr << "Cannot read rootservers/" << *sn << std::endl;
- return 1;
- }
- rootservers[*sn] = buf;
- }
- }
- topology["rootservers"] = rootservers.toString();
-
- if ((topologyAuthority)&&(topologyAuthority.hasPrivate())) {
- // Sign topology with root-topology-authority.secret
- if (!topology.sign(topologyAuthority,OSUtils::now())) {
- std::cerr << "Unable to sign!" << std::endl;
- return 1;
- }
-
- // Test signature to make sure signing worked
- Dictionary test(topology.toString());
- if (!test.verify(topologyAuthority)) {
- std::cerr << "Test verification of signed dictionary failed!" << std::endl;
- return 1;
- }
- }
-
- // Output to stdout
- std::cout << topology.toString();
-
- return 0;
-}
diff --git a/root-topology/rootservers/7e19876aba b/root-topology/rootservers/7e19876aba
deleted file mode 100644
index 6bd8dc42..00000000
--- a/root-topology/rootservers/7e19876aba
+++ /dev/null
@@ -1,4 +0,0 @@
-id=7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa
-udp=198.199.97.220/9993
-tcp=198.199.97.220/443
-desc=San Francisco, California, USA
diff --git a/root-topology/rootservers/8841408a2e b/root-topology/rootservers/8841408a2e
deleted file mode 100644
index 3be3333e..00000000
--- a/root-topology/rootservers/8841408a2e
+++ /dev/null
@@ -1,4 +0,0 @@
-id=8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c
-udp=107.191.46.210/9993
-tcp=107.191.46.210/443
-desc=Paris, France
diff --git a/root-topology/rootservers/8acf059fe3 b/root-topology/rootservers/8acf059fe3
deleted file mode 100644
index 4a569d95..00000000
--- a/root-topology/rootservers/8acf059fe3
+++ /dev/null
@@ -1,4 +0,0 @@
-id=8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5
-udp=162.243.77.111/9993
-tcp=162.243.77.111/443
-desc=New York, New York, USA
diff --git a/root-topology/rootservers/9d219039f3 b/root-topology/rootservers/9d219039f3
deleted file mode 100644
index ec922433..00000000
--- a/root-topology/rootservers/9d219039f3
+++ /dev/null
@@ -1,4 +0,0 @@
-id=9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e
-udp=128.199.197.217/9993
-tcp=128.199.197.217/443
-desc=Singapore
diff --git a/root-topology/test/README.md b/root-topology/test/README.md
deleted file mode 100644
index ae702243..00000000
--- a/root-topology/test/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Test Root Topology Script
-======
-
-This builds a test-root-topology from any number of running test-rootserver-# Docker containers. This can then be used with the (undocumented) -T (override root topology) option to run test networks under Docker.
-
-Once you have a local Docker test network running you can use iptables rules to simulate a variety of network pathologies, or you can just use it to test any new changes to the protocol or node behavior at some limited scale.
diff --git a/root-topology/test/create-test-root-topology.sh b/root-topology/test/create-test-root-topology.sh
deleted file mode 100755
index cb628729..00000000
--- a/root-topology/test/create-test-root-topology.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-if [ ! -e ../mktopology ]; then
- echo 'Build ../mktopology first!'
- exit 1
-fi
-
-echo 'Populating rootservers/* with all Docker test-rootserver-* container IPs and identities...'
-
-rm -rf rootservers
-mkdir rootservers
-
-for cid in `docker ps -f 'name=test-rootserver-*' -q`; do
- id=`docker exec $cid cat /var/lib/zerotier-one/identity.secret | cut -d : -f 1-3`
- ztaddr=`echo $id | cut -d : -f 1`
- ip=`docker exec $cid ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'`
- echo $cid $ztaddr $id $ip
- echo "id=$id" >rootservers/$ztaddr
- echo "udp=$ip/9993" >>rootservers/$ztaddr
-done
-
-echo 'Creating test-root-topology...'
-
-rm -f test-root-topology
-../mktopology >test-root-topology
-
-echo 'Done!'
-echo
-cat test-root-topology
-
-exit 0
diff --git a/selftest.cpp b/selftest.cpp
index 145e797b..87043ddd 100644
--- a/selftest.cpp
+++ b/selftest.cpp
@@ -41,6 +41,7 @@
#include "node/InetAddress.hpp"
#include "node/Utils.hpp"
#include "node/Identity.hpp"
+#include "node/Buffer.hpp"
#include "node/Packet.hpp"
#include "node/Salsa20.hpp"
#include "node/MAC.hpp"
@@ -50,8 +51,8 @@
#include "node/C25519.hpp"
#include "node/Poly1305.hpp"
#include "node/CertificateOfMembership.hpp"
-#include "node/Defaults.hpp"
#include "node/Node.hpp"
+#include "node/IncomingPacket.hpp"
#include "osdep/OSUtils.hpp"
#include "osdep/Phy.hpp"
@@ -161,27 +162,27 @@ static int testCrypto()
memset(buf2,0,sizeof(buf2));
memset(buf3,0,sizeof(buf3));
Salsa20 s20;
- s20.init("12345678123456781234567812345678",256,"12345678",20);
- s20.encrypt(buf1,buf2,sizeof(buf1));
- s20.init("12345678123456781234567812345678",256,"12345678",20);
- s20.decrypt(buf2,buf3,sizeof(buf2));
+ s20.init("12345678123456781234567812345678",256,"12345678");
+ s20.encrypt20(buf1,buf2,sizeof(buf1));
+ s20.init("12345678123456781234567812345678",256,"12345678");
+ s20.decrypt20(buf2,buf3,sizeof(buf2));
if (memcmp(buf1,buf3,sizeof(buf1))) {
std::cout << "FAIL (encrypt/decrypt test)" << std::endl;
return -1;
}
}
- Salsa20 s20(s20TV0Key,256,s20TV0Iv,20);
+ Salsa20 s20(s20TV0Key,256,s20TV0Iv);
memset(buf1,0,sizeof(buf1));
memset(buf2,0,sizeof(buf2));
- s20.encrypt(buf1,buf2,64);
+ s20.encrypt20(buf1,buf2,64);
if (memcmp(buf2,s20TV0Ks,64)) {
std::cout << "FAIL (test vector 0)" << std::endl;
return -1;
}
- s20.init(s2012TV0Key,256,s2012TV0Iv,12);
+ s20.init(s2012TV0Key,256,s2012TV0Iv);
memset(buf1,0,sizeof(buf1));
memset(buf2,0,sizeof(buf2));
- s20.encrypt(buf1,buf2,64);
+ s20.encrypt12(buf1,buf2,64);
if (memcmp(buf2,s2012TV0Ks,64)) {
std::cout << "FAIL (test vector 1)" << std::endl;
return -1;
@@ -194,34 +195,16 @@ static int testCrypto()
std::cout << "[crypto] Salsa20 SSE: DISABLED" << std::endl;
#endif
- std::cout << "[crypto] Benchmarking Salsa20/8... "; std::cout.flush();
- {
- unsigned char *bb = (unsigned char *)::malloc(1234567);
- for(unsigned int i=0;i<1234567;++i)
- bb[i] = (unsigned char)i;
- Salsa20 s20(s20TV0Key,256,s20TV0Iv,8);
- double bytes = 0.0;
- uint64_t start = OSUtils::now();
- for(unsigned int i=0;i<200;++i) {
- s20.encrypt(bb,bb,1234567);
- bytes += 1234567.0;
- }
- uint64_t end = OSUtils::now();
- SHA512::hash(buf1,bb,1234567);
- std::cout << ((bytes / 1048576.0) / ((double)(end - start) / 1000.0)) << " MiB/second (" << Utils::hex(buf1,16) << ')' << std::endl;
- ::free((void *)bb);
- }
-
std::cout << "[crypto] Benchmarking Salsa20/12... "; std::cout.flush();
{
unsigned char *bb = (unsigned char *)::malloc(1234567);
for(unsigned int i=0;i<1234567;++i)
bb[i] = (unsigned char)i;
- Salsa20 s20(s20TV0Key,256,s20TV0Iv,12);
+ Salsa20 s20(s20TV0Key,256,s20TV0Iv);
double bytes = 0.0;
uint64_t start = OSUtils::now();
for(unsigned int i=0;i<200;++i) {
- s20.encrypt(bb,bb,1234567);
+ s20.encrypt12(bb,bb,1234567);
bytes += 1234567.0;
}
uint64_t end = OSUtils::now();
@@ -235,11 +218,11 @@ static int testCrypto()
unsigned char *bb = (unsigned char *)::malloc(1234567);
for(unsigned int i=0;i<1234567;++i)
bb[i] = (unsigned char)i;
- Salsa20 s20(s20TV0Key,256,s20TV0Iv,20);
+ Salsa20 s20(s20TV0Key,256,s20TV0Iv);
double bytes = 0.0;
uint64_t start = OSUtils::now();
for(unsigned int i=0;i<200;++i) {
- s20.encrypt(bb,bb,1234567);
+ s20.encrypt20(bb,bb,1234567);
bytes += 1234567.0;
}
uint64_t end = OSUtils::now();
@@ -285,6 +268,19 @@ static int testCrypto()
::free((void *)bb);
}
+ /*
+ for(unsigned int d=8;d<=10;++d) {
+ for(int k=0;k<8;++k) {
+ std::cout << "[crypto] computeSalsa2012Sha512ProofOfWork(" << d << ",\"foobarbaz\",9) == "; std::cout.flush();
+ unsigned char result[16];
+ uint64_t start = OSUtils::now();
+ IncomingPacket::computeSalsa2012Sha512ProofOfWork(d,"foobarbaz",9,result);
+ uint64_t end = OSUtils::now();
+ std::cout << Utils::hex(result,16) << " -- valid: " << IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(d,"foobarbaz",9,result) << ", " << (end - start) << "ms" << std::endl;
+ }
+ }
+ */
+
std::cout << "[crypto] Testing C25519 and Ed25519 against test vectors... "; std::cout.flush();
for(int k=0;k<ZT_NUM_C25519_TEST_VECTORS;++k) {
C25519::Pair p1,p2;
@@ -598,23 +594,44 @@ static int testOther()
std::cout << "[other] Testing Hashtable... "; std::cout.flush();
{
Hashtable<uint64_t,std::string> ht;
- Hashtable<uint64_t,std::string> ht2;
std::map<uint64_t,std::string> ref; // assume std::map works correctly :)
for(int x=0;x<2;++x) {
- for(int i=0;i<25000;++i) {
+ for(int i=0;i<77777;++i) {
uint64_t k = rand();
while ((k == 0)||(ref.count(k) > 0))
++k;
std::string v("!");
for(int j=0;j<(int)(k % 64);++j)
v.push_back("0123456789"[rand() % 10]);
- ht.set(k,v);
ref[k] = v;
+ ht.set(0xffffffffffffffffULL,v);
+ std::string &vref = ht[k];
+ vref = v;
+ ht.erase(0xffffffffffffffffULL);
}
if (ht.size() != ref.size()) {
std::cout << "FAILED! (size mismatch, original)" << std::endl;
return -1;
}
+ {
+ Hashtable<uint64_t,std::string>::Iterator i(ht);
+ uint64_t *k = (uint64_t *)0;
+ std::string *v = (std::string *)0;
+ while(i.next(k,v)) {
+ if (ref.find(*k)->second != *v) {
+ std::cout << "FAILED! (data mismatch!)" << std::endl;
+ return -1;
+ }
+ }
+ }
+ for(std::map<uint64_t,std::string>::const_iterator i(ref.begin());i!=ref.end();++i) {
+ if (ht[i->first] != i->second) {
+ std::cout << "FAILED! (data mismatch!)" << std::endl;
+ return -1;
+ }
+ }
+
+ Hashtable<uint64_t,std::string> ht2;
ht2 = ht;
Hashtable<uint64_t,std::string> ht3(ht2);
if (ht2.size() != ref.size()) {
@@ -625,6 +642,7 @@ static int testOther()
std::cout << "FAILED! (size mismatch, copied)" << std::endl;
return -1;
}
+
for(std::map<uint64_t,std::string>::iterator i(ref.begin());i!=ref.end();++i) {
std::string *v = ht.get(i->first);
if (!v) {
@@ -837,14 +855,14 @@ struct TestPhyHandlers
}
}
- inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {}
-
#ifdef __UNIX_LIKE__
inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {}
inline void phyOnUnixClose(PhySocket *sock,void **uptr) {}
inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {}
#endif // __UNIX_LIKE__
+
+ inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {}
};
static int testPhy()
{
diff --git a/service/ClusterDefinition.hpp b/service/ClusterDefinition.hpp
new file mode 100644
index 00000000..d02894e4
--- /dev/null
+++ b/service/ClusterDefinition.hpp
@@ -0,0 +1,125 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_CLUSTERDEFINITION_HPP
+#define ZT_CLUSTERDEFINITION_HPP
+
+#ifdef ZT_ENABLE_CLUSTER
+
+#include <vector>
+#include <algorithm>
+
+#include "../node/Constants.hpp"
+#include "../node/Utils.hpp"
+#include "../osdep/OSUtils.hpp"
+
+namespace ZeroTier {
+
+/**
+ * Parser for cluster definition file
+ */
+class ClusterDefinition
+{
+public:
+ struct MemberDefinition
+ {
+ MemberDefinition() : id(0),x(0),y(0),z(0) { name[0] = (char)0; }
+
+ unsigned int id;
+ int x,y,z;
+ char name[256];
+ InetAddress clusterEndpoint;
+ std::vector<InetAddress> zeroTierEndpoints;
+ };
+
+ ClusterDefinition(uint64_t myAddress,const char *pathToClusterFile)
+ {
+ std::string cf;
+ if (!OSUtils::readFile(pathToClusterFile,cf))
+ return;
+
+ char myAddressStr[64];
+ Utils::snprintf(myAddressStr,sizeof(myAddressStr),"%.10llx",myAddress);
+
+ std::vector<std::string> lines(Utils::split(cf.c_str(),"\r\n","",""));
+ for(std::vector<std::string>::iterator l(lines.begin());l!=lines.end();++l) {
+ std::vector<std::string> fields(Utils::split(l->c_str()," \t","",""));
+ if ((fields.size() < 5)||(fields[0][0] == '#')||(fields[0] != myAddressStr))
+ continue;
+
+ int id = Utils::strToUInt(fields[1].c_str());
+ if ((id < 0)||(id > ZT_CLUSTER_MAX_MEMBERS))
+ continue;
+ MemberDefinition &md = _md[id];
+
+ md.id = (unsigned int)id;
+ if (fields.size() >= 6) {
+ std::vector<std::string> xyz(Utils::split(fields[5].c_str(),",","",""));
+ md.x = (xyz.size() > 0) ? Utils::strToInt(xyz[0].c_str()) : 0;
+ md.y = (xyz.size() > 1) ? Utils::strToInt(xyz[1].c_str()) : 0;
+ md.z = (xyz.size() > 2) ? Utils::strToInt(xyz[2].c_str()) : 0;
+ }
+ Utils::scopy(md.name,sizeof(md.name),fields[2].c_str());
+ md.clusterEndpoint.fromString(fields[3]);
+ if (!md.clusterEndpoint)
+ continue;
+ std::vector<std::string> zips(Utils::split(fields[4].c_str(),",","",""));
+ for(std::vector<std::string>::iterator zip(zips.begin());zip!=zips.end();++zip) {
+ InetAddress i;
+ i.fromString(*zip);
+ if (i)
+ md.zeroTierEndpoints.push_back(i);
+ }
+
+ _ids.push_back((unsigned int)id);
+ }
+
+ std::sort(_ids.begin(),_ids.end());
+ }
+
+ inline const MemberDefinition &operator[](unsigned int id) const throw() { return _md[id]; }
+ inline unsigned int size() const throw() { return (unsigned int)_ids.size(); }
+ inline const std::vector<unsigned int> &ids() const throw() { return _ids; }
+
+ inline std::vector<MemberDefinition> members() const
+ {
+ std::vector<MemberDefinition> m;
+ for(std::vector<unsigned int>::const_iterator i(_ids.begin());i!=_ids.end();++i)
+ m.push_back(_md[*i]);
+ return m;
+ }
+
+private:
+ MemberDefinition _md[ZT_CLUSTER_MAX_MEMBERS];
+ std::vector<unsigned int> _ids;
+};
+
+} // namespace ZeroTier
+
+#endif // ZT_ENABLE_CLUSTER
+
+#endif
diff --git a/service/ClusterGeoIpService.cpp b/service/ClusterGeoIpService.cpp
new file mode 100644
index 00000000..f646fe99
--- /dev/null
+++ b/service/ClusterGeoIpService.cpp
@@ -0,0 +1,197 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifdef ZT_ENABLE_CLUSTER
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <iostream>
+
+#include "ClusterGeoIpService.hpp"
+#include "../node/Utils.hpp"
+#include "../osdep/OSUtils.hpp"
+
+// 120 days
+#define ZT_CLUSTERGEOIPSERVICE_INTERNAL_CACHE_TTL 10368000000ULL
+
+namespace ZeroTier {
+
+ClusterGeoIpService::ClusterGeoIpService(const char *pathToExe) :
+ _pathToExe(pathToExe),
+ _sOutputFd(-1),
+ _sInputFd(-1),
+ _sPid(0),
+ _run(true)
+{
+ _thread = Thread::start(this);
+}
+
+ClusterGeoIpService::~ClusterGeoIpService()
+{
+ _run = false;
+ long p = _sPid;
+ if (p > 0) {
+ ::kill(p,SIGTERM);
+ Thread::sleep(500);
+ ::kill(p,SIGKILL);
+ }
+ Thread::join(_thread);
+}
+
+bool ClusterGeoIpService::locate(const InetAddress &ip,int &x,int &y,int &z)
+{
+ InetAddress ipNoPort(ip);
+ ipNoPort.setPort(0); // we index cache by IP only
+ const uint64_t now = OSUtils::now();
+
+ bool r = false;
+ {
+ Mutex::Lock _l(_cache_m);
+ std::map< InetAddress,_CE >::iterator c(_cache.find(ipNoPort));
+ if (c != _cache.end()) {
+ x = c->second.x;
+ y = c->second.y;
+ z = c->second.z;
+ if ((now - c->second.ts) < ZT_CLUSTERGEOIPSERVICE_INTERNAL_CACHE_TTL)
+ return true;
+ else r = true; // return true but refresh as well
+ }
+ }
+
+ {
+ Mutex::Lock _l(_sOutputLock);
+ if (_sOutputFd >= 0) {
+ std::string ips(ipNoPort.toIpString());
+ ips.push_back('\n');
+ //fprintf(stderr,"ClusterGeoIpService: << %s",ips.c_str());
+ ::write(_sOutputFd,ips.data(),ips.length());
+ }
+ }
+
+ return r;
+}
+
+void ClusterGeoIpService::threadMain()
+ throw()
+{
+ char linebuf[65536];
+ char buf[65536];
+ long n,lineptr;
+
+ while (_run) {
+ {
+ Mutex::Lock _l(_sOutputLock);
+
+ _sOutputFd = -1;
+ _sInputFd = -1;
+ _sPid = 0;
+
+ int stdinfds[2] = { 0,0 }; // sub-process's stdin, our output
+ int stdoutfds[2] = { 0,0 }; // sub-process's stdout, our input
+ ::pipe(stdinfds);
+ ::pipe(stdoutfds);
+
+ long p = (long)::vfork();
+ if (p < 0) {
+ Thread::sleep(500);
+ continue;
+ } else if (p == 0) {
+ ::close(stdinfds[1]);
+ ::close(stdoutfds[0]);
+ ::dup2(stdinfds[0],STDIN_FILENO);
+ ::dup2(stdoutfds[1],STDOUT_FILENO);
+ ::execl(_pathToExe.c_str(),_pathToExe.c_str(),(const char *)0);
+ ::exit(1);
+ } else {
+ ::close(stdinfds[0]);
+ ::close(stdoutfds[1]);
+ _sOutputFd = stdinfds[1];
+ _sInputFd = stdoutfds[0];
+ _sPid = p;
+ }
+ }
+
+ lineptr = 0;
+ while (_run) {
+ n = ::read(_sInputFd,buf,sizeof(buf));
+ if (n <= 0) {
+ if (errno == EINTR)
+ continue;
+ else break;
+ }
+ for(long i=0;i<n;++i) {
+ if (lineptr > (long)sizeof(linebuf))
+ lineptr = 0;
+ if ((buf[i] == '\n')||(buf[i] == '\r')) {
+ linebuf[lineptr] = (char)0;
+ if (lineptr > 0) {
+ //fprintf(stderr,"ClusterGeoIpService: >> %s\n",linebuf);
+ try {
+ std::vector<std::string> result(Utils::split(linebuf,",","",""));
+ if ((result.size() >= 7)&&(result[1] == "1")) {
+ InetAddress rip(result[0],0);
+ if ((rip.ss_family == AF_INET)||(rip.ss_family == AF_INET6)) {
+ _CE ce;
+ ce.ts = OSUtils::now();
+ ce.x = (int)::strtol(result[4].c_str(),(char **)0,10);
+ ce.y = (int)::strtol(result[5].c_str(),(char **)0,10);
+ ce.z = (int)::strtol(result[6].c_str(),(char **)0,10);
+ //fprintf(stderr,"ClusterGeoIpService: %s is at %d,%d,%d\n",rip.toIpString().c_str(),ce.x,ce.y,ce.z);
+ {
+ Mutex::Lock _l2(_cache_m);
+ _cache[rip] = ce;
+ }
+ }
+ }
+ } catch ( ... ) {}
+ }
+ lineptr = 0;
+ } else linebuf[lineptr++] = buf[i];
+ }
+ }
+
+ ::close(_sOutputFd);
+ ::close(_sInputFd);
+ ::kill(_sPid,SIGTERM);
+ Thread::sleep(250);
+ ::kill(_sPid,SIGKILL);
+ ::waitpid(_sPid,(int *)0,0);
+ }
+}
+
+} // namespace ZeroTier
+
+#endif // ZT_ENABLE_CLUSTER
diff --git a/service/ClusterGeoIpService.hpp b/service/ClusterGeoIpService.hpp
new file mode 100644
index 00000000..fd04ba1d
--- /dev/null
+++ b/service/ClusterGeoIpService.hpp
@@ -0,0 +1,94 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_CLUSTERGEOIPSERVICE_HPP
+#define ZT_CLUSTERGEOIPSERVICE_HPP
+
+#ifdef ZT_ENABLE_CLUSTER
+
+#include <vector>
+#include <map>
+#include <string>
+
+#include "../node/Constants.hpp"
+#include "../node/InetAddress.hpp"
+#include "../node/Mutex.hpp"
+#include "../osdep/Thread.hpp"
+
+namespace ZeroTier {
+
+/**
+ * Runs the Cluster GeoIP service in the background and resolves geoIP queries
+ */
+class ClusterGeoIpService
+{
+public:
+ /**
+ * @param pathToExe Path to cluster geo-resolution service executable
+ */
+ ClusterGeoIpService(const char *pathToExe);
+
+ ~ClusterGeoIpService();
+
+ /**
+ * Attempt to locate an IP
+ *
+ * This returns true if x, y, and z are set. Otherwise it returns false
+ * and a geo-locate job is ordered in the background. This usually takes
+ * 500-1500ms to complete, after which time results will be available.
+ * If false is returned the supplied coordinate variables are unchanged.
+ *
+ * @param ip IPv4 or IPv6 address
+ * @param x Reference to variable to receive X
+ * @param y Reference to variable to receive Y
+ * @param z Reference to variable to receive Z
+ * @return True if coordinates were set
+ */
+ bool locate(const InetAddress &ip,int &x,int &y,int &z);
+
+ void threadMain()
+ throw();
+
+private:
+ const std::string _pathToExe;
+ int _sOutputFd;
+ int _sInputFd;
+ volatile long _sPid;
+ volatile bool _run;
+ Thread _thread;
+ Mutex _sOutputLock;
+
+ struct _CE { uint64_t ts; int x,y,z; };
+ std::map< InetAddress,_CE > _cache;
+ Mutex _cache_m;
+};
+
+} // namespace ZeroTier
+
+#endif // ZT_ENABLE_CLUSTER
+
+#endif
diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp
index 6e731bdc..4978a91d 100644
--- a/service/ControlPlane.cpp
+++ b/service/ControlPlane.cpp
@@ -182,14 +182,12 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath *
"%s\t\"address\": \"%s\",\n"
"%s\t\"lastSend\": %llu,\n"
"%s\t\"lastReceive\": %llu,\n"
- "%s\t\"fixed\": %s,\n"
"%s\t\"active\": %s,\n"
"%s\t\"preferred\": %s\n"
"%s}",
prefix,_jsonEscape(reinterpret_cast<const InetAddress *>(&(pp[i].address))->toString()).c_str(),
prefix,pp[i].lastSend,
prefix,pp[i].lastReceive,
- prefix,(pp[i].fixed == 0) ? "false" : "true",
prefix,(pp[i].active == 0) ? "false" : "true",
prefix,(pp[i].preferred == 0) ? "false" : "true",
prefix);
@@ -267,7 +265,7 @@ unsigned int ControlPlane::handleRequest(
std::string &responseBody,
std::string &responseContentType)
{
- char json[1024];
+ char json[8194];
unsigned int scode = 404;
std::vector<std::string> ps(Utils::split(path.c_str(),"/","",""));
std::map<std::string,std::string> urlArgs;
@@ -356,29 +354,65 @@ unsigned int ControlPlane::handleRequest(
if (ps[0] == "status") {
responseContentType = "application/json";
+
ZT_NodeStatus status;
_node->status(&status);
+
+ std::string clusterJson;
+#ifdef ZT_ENABLE_CLUSTER
+ {
+ ZT_ClusterStatus cs;
+ _node->clusterStatus(&cs);
+
+ if (cs.clusterSize >= 1) {
+ char t[1024];
+ Utils::snprintf(t,sizeof(t),"{\n\t\t\"myId\": %u,\n\t\t\"clusterSize\": %u,\n\t\t\"members\": [",cs.myId,cs.clusterSize);
+ clusterJson.append(t);
+ for(unsigned int i=0;i<cs.clusterSize;++i) {
+ Utils::snprintf(t,sizeof(t),"%s\t\t\t{\n\t\t\t\t\"id\": %u,\n\t\t\t\t\"msSinceLastHeartbeat\": %u,\n\t\t\t\t\"alive\": %s,\n\t\t\t\t\"x\": %d,\n\t\t\t\t\"y\": %d,\n\t\t\t\t\"z\": %d,\n\t\t\t\t\"load\": %llu,\n\t\t\t\t\"peers\": %llu\n\t\t\t}",
+ ((i == 0) ? "\n" : ",\n"),
+ cs.members[i].id,
+ cs.members[i].msSinceLastHeartbeat,
+ (cs.members[i].alive != 0) ? "true" : "false",
+ cs.members[i].x,
+ cs.members[i].y,
+ cs.members[i].z,
+ cs.members[i].load,
+ cs.members[i].peers);
+ clusterJson.append(t);
+ }
+ clusterJson.append(" ]\n\t\t}");
+ }
+ }
+#endif
+
Utils::snprintf(json,sizeof(json),
"{\n"
"\t\"address\": \"%.10llx\",\n"
"\t\"publicIdentity\": \"%s\",\n"
+ "\t\"worldId\": %llu,\n"
+ "\t\"worldTimestamp\": %llu,\n"
"\t\"online\": %s,\n"
"\t\"tcpFallbackActive\": %s,\n"
"\t\"versionMajor\": %d,\n"
"\t\"versionMinor\": %d,\n"
"\t\"versionRev\": %d,\n"
"\t\"version\": \"%d.%d.%d\",\n"
- "\t\"clock\": %llu\n"
+ "\t\"clock\": %llu,\n"
+ "\t\"cluster\": %s\n"
"}\n",
status.address,
status.publicIdentity,
+ status.worldId,
+ status.worldTimestamp,
(status.online) ? "true" : "false",
(_svc->tcpFallbackActive()) ? "true" : "false",
ZEROTIER_ONE_VERSION_MAJOR,
ZEROTIER_ONE_VERSION_MINOR,
ZEROTIER_ONE_VERSION_REVISION,
ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,
- (unsigned long long)OSUtils::now());
+ (unsigned long long)OSUtils::now(),
+ ((clusterJson.length() > 0) ? clusterJson.c_str() : "null"));
responseBody = json;
scode = 200;
} else if (ps[0] == "config") {
diff --git a/service/OneService.cpp b/service/OneService.cpp
index d194b400..fd473429 100644
--- a/service/OneService.cpp
+++ b/service/OneService.cpp
@@ -58,6 +58,8 @@
#include "OneService.hpp"
#include "ControlPlane.hpp"
+#include "ClusterGeoIpService.hpp"
+#include "ClusterDefinition.hpp"
/**
* Uncomment to enable UDP breakage switch
@@ -378,9 +380,14 @@ static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,uint64_t n
static void SnodeEventCallback(ZT_Node *node,void *uptr,enum ZT_Event event,const void *metaData);
static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize);
static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure);
-static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len);
+static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl);
static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
+#ifdef ZT_ENABLE_CLUSTER
+static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len);
+static int SclusterGeoIpFunction(void *uptr,const struct sockaddr_storage *addr,int *x,int *y,int *z);
+#endif
+
static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
static int ShttpOnMessageBegin(http_parser *parser);
@@ -430,31 +437,45 @@ struct TcpConnection
Mutex writeBuf_m;
};
+// Use a bigger buffer on AMD64 since these are likely to be bigger and
+// servers. Otherwise use a smaller buffer. This makes no difference
+// except under very high load.
+#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__))
+#define ZT_UDP_DESIRED_BUF_SIZE 1048576
+#else
+#define ZT_UDP_DESIRED_BUF_SIZE 131072
+#endif
+
class OneServiceImpl : public OneService
{
public:
- OneServiceImpl(const char *hp,unsigned int port,const char *overrideRootTopology) :
- _homePath((hp) ? hp : "."),
- _tcpFallbackResolver(ZT_TCP_FALLBACK_RELAY),
+ OneServiceImpl(const char *hp,unsigned int port) :
+ _homePath((hp) ? hp : ".")
+ ,_tcpFallbackResolver(ZT_TCP_FALLBACK_RELAY)
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
- _controller((SqliteNetworkController *)0),
+ ,_controller((SqliteNetworkController *)0)
#endif
- _phy(this,false,true),
- _overrideRootTopology((overrideRootTopology) ? overrideRootTopology : ""),
- _node((Node *)0),
- _controlPlane((ControlPlane *)0),
- _lastDirectReceiveFromGlobal(0),
- _lastSendToGlobal(0),
- _lastRestart(0),
- _nextBackgroundTaskDeadline(0),
- _tcpFallbackTunnel((TcpConnection *)0),
- _termReason(ONE_STILL_RUNNING),
- _port(0),
+ ,_phy(this,false,true)
+ ,_node((Node *)0)
+ ,_controlPlane((ControlPlane *)0)
+ ,_lastDirectReceiveFromGlobal(0)
+ ,_lastSendToGlobal(0)
+ ,_lastRestart(0)
+ ,_nextBackgroundTaskDeadline(0)
+ ,_tcpFallbackTunnel((TcpConnection *)0)
+ ,_termReason(ONE_STILL_RUNNING)
+ ,_port(0)
#ifdef ZT_USE_MINIUPNPC
- _v4UpnpUdpSocket((PhySocket *)0),
- _upnpClient((UPNPClient *)0),
+ ,_v4UpnpUdpSocket((PhySocket *)0)
+ ,_upnpClient((UPNPClient *)0)
#endif
- _run(true)
+#ifdef ZT_ENABLE_CLUSTER
+ ,_clusterMessageSocket((PhySocket *)0)
+ ,_clusterGeoIpService((ClusterGeoIpService *)0)
+ ,_clusterDefinition((ClusterDefinition *)0)
+ ,_clusterMemberId(0)
+#endif
+ ,_run(true)
{
const int portTrials = (port == 0) ? 256 : 1; // if port is 0, pick random
for(int k=0;k<portTrials;++k) {
@@ -465,7 +486,7 @@ public:
}
_v4LocalAddress = InetAddress((uint32_t)0,port);
- _v4UdpSocket = _phy.udpBind((const struct sockaddr *)&_v4LocalAddress,reinterpret_cast<void *>(&_v4LocalAddress),131072);
+ _v4UdpSocket = _phy.udpBind((const struct sockaddr *)&_v4LocalAddress,reinterpret_cast<void *>(&_v4LocalAddress),ZT_UDP_DESIRED_BUF_SIZE);
if (_v4UdpSocket) {
struct sockaddr_in in4;
@@ -477,7 +498,7 @@ public:
if (_v4TcpListenSocket) {
_v6LocalAddress = InetAddress("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16,port);
- _v6UdpSocket = _phy.udpBind((const struct sockaddr *)&_v6LocalAddress,reinterpret_cast<void *>(&_v6LocalAddress),131072);
+ _v6UdpSocket = _phy.udpBind((const struct sockaddr *)&_v6LocalAddress,reinterpret_cast<void *>(&_v6LocalAddress),ZT_UDP_DESIRED_BUF_SIZE);
struct sockaddr_in6 in6;
memset((void *)&in6,0,sizeof(in6));
@@ -511,7 +532,7 @@ public:
for(int k=0;k<512;++k) {
const unsigned int upnport = 40000 + (((port + 1) * (k + 1)) % 25500);
_v4UpnpLocalAddress = InetAddress(0,upnport);
- _v4UpnpUdpSocket = _phy.udpBind((const struct sockaddr *)&_v4UpnpLocalAddress,reinterpret_cast<void *>(&_v4UpnpLocalAddress),131072);
+ _v4UpnpUdpSocket = _phy.udpBind((const struct sockaddr *)&_v4UpnpLocalAddress,reinterpret_cast<void *>(&_v4UpnpLocalAddress),ZT_UDP_DESIRED_BUF_SIZE);
if (_v4UpnpUdpSocket) {
_upnpClient = new UPNPClient(upnport);
break;
@@ -526,6 +547,9 @@ public:
_phy.close(_v6UdpSocket);
_phy.close(_v4TcpListenSocket);
_phy.close(_v6TcpListenSocket);
+#ifdef ZT_ENABLE_CLUSTER
+ _phy.close(_clusterMessageSocket);
+#endif
#ifdef ZT_USE_MINIUPNPC
_phy.close(_v4UpnpUdpSocket);
delete _upnpClient;
@@ -533,6 +557,10 @@ public:
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
delete _controller;
#endif
+#ifdef ZT_ENABLE_CLUSTER
+ delete _clusterGeoIpService;
+ delete _clusterDefinition;
+#endif
}
virtual ReasonForTermination run()
@@ -565,14 +593,77 @@ public:
SnodeWirePacketSendFunction,
SnodeVirtualNetworkFrameFunction,
SnodeVirtualNetworkConfigFunction,
- SnodeEventCallback,
- ((_overrideRootTopology.length() > 0) ? _overrideRootTopology.c_str() : (const char *)0));
+ SnodeEventCallback);
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
_controller = new SqliteNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str(),(_homePath + ZT_PATH_SEPARATOR_S + "circuitTestResults.d").c_str());
_node->setNetconfMaster((void *)_controller);
#endif
+#ifdef ZT_ENABLE_CLUSTER
+ if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str())) {
+ _clusterDefinition = new ClusterDefinition(_node->address(),(_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str());
+ if (_clusterDefinition->size() > 0) {
+ std::vector<ClusterDefinition::MemberDefinition> members(_clusterDefinition->members());
+ for(std::vector<ClusterDefinition::MemberDefinition>::iterator m(members.begin());m!=members.end();++m) {
+ PhySocket *cs = _phy.udpBind(reinterpret_cast<const struct sockaddr *>(&(m->clusterEndpoint)));
+ if (cs) {
+ if (_clusterMessageSocket) {
+ _phy.close(_clusterMessageSocket,false);
+ _phy.close(cs,false);
+
+ Mutex::Lock _l(_termReason_m);
+ _termReason = ONE_UNRECOVERABLE_ERROR;
+ _fatalErrorMessage = "Cluster: can't determine my cluster member ID: able to bind more than one cluster message socket IP/port!";
+ return _termReason;
+ }
+ _clusterMessageSocket = cs;
+ _clusterMemberId = m->id;
+ }
+ }
+
+ if (!_clusterMessageSocket) {
+ Mutex::Lock _l(_termReason_m);
+ _termReason = ONE_UNRECOVERABLE_ERROR;
+ _fatalErrorMessage = "Cluster: can't determine my cluster member ID: unable to bind to any cluster message socket IP/port.";
+ return _termReason;
+ }
+
+ if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S + "cluster-geo.exe").c_str()))
+ _clusterGeoIpService = new ClusterGeoIpService((_homePath + ZT_PATH_SEPARATOR_S + "cluster-geo.exe").c_str());
+
+ const ClusterDefinition::MemberDefinition &me = (*_clusterDefinition)[_clusterMemberId];
+ InetAddress endpoints[255];
+ unsigned int numEndpoints = 0;
+ for(std::vector<InetAddress>::const_iterator i(me.zeroTierEndpoints.begin());i!=me.zeroTierEndpoints.end();++i)
+ endpoints[numEndpoints++] = *i;
+
+ if (_node->clusterInit(
+ _clusterMemberId,
+ reinterpret_cast<const struct sockaddr_storage *>(endpoints),
+ numEndpoints,
+ me.x,
+ me.y,
+ me.z,
+ &SclusterSendFunction,
+ this,
+ (_clusterGeoIpService) ? &SclusterGeoIpFunction : 0,
+ this) == ZT_RESULT_OK) {
+
+ std::vector<ClusterDefinition::MemberDefinition> members(_clusterDefinition->members());
+ for(std::vector<ClusterDefinition::MemberDefinition>::iterator m(members.begin());m!=members.end();++m) {
+ if (m->id != _clusterMemberId)
+ _node->clusterAddMember(m->id);
+ }
+
+ }
+ } else {
+ delete _clusterDefinition;
+ _clusterDefinition = (ClusterDefinition *)0;
+ }
+ }
+#endif
+
_controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S + "ui").c_str());
_controlPlane->addAuthToken(authToken.c_str());
@@ -589,6 +680,10 @@ public:
}
}
+ // Start two background threads to handle expensive ops out of line
+ Thread::start(_node);
+ Thread::start(_node);
+
_nextBackgroundTaskDeadline = 0;
uint64_t clockShouldBe = OSUtils::now();
_lastRestart = clockShouldBe;
@@ -664,7 +759,7 @@ public:
#ifdef ZT_USE_MINIUPNPC
std::vector<InetAddress> upnpAddresses(_upnpClient->get());
for(std::vector<InetAddress>::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext)
- _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*ext)),0,ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL);
+ _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*ext)));
#endif
struct ifaddrs *ifatbl = (struct ifaddrs *)0;
@@ -682,7 +777,7 @@ public:
if (!isZT) {
InetAddress ip(ifa->ifa_addr);
ip.setPort(_port);
- _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&ip),0,ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL);
+ _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&ip));
}
}
ifa = ifa->ifa_next;
@@ -716,7 +811,7 @@ public:
while (ua) {
InetAddress ip(ua->Address.lpSockaddr);
ip.setPort(_port);
- _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&ip),0,ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL);
+ _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&ip));
ua = ua->Next;
}
}
@@ -798,10 +893,19 @@ public:
inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len)
{
+#ifdef ZT_ENABLE_CLUSTER
+ if (sock == _clusterMessageSocket) {
+ _lastDirectReceiveFromGlobal = OSUtils::now();
+ _node->clusterHandleIncomingMessage(data,len);
+ return;
+ }
+#endif
+
#ifdef ZT_BREAK_UDP
if (OSUtils::fileExists("/tmp/ZT_BREAK_UDP"))
return;
#endif
+
if ((len >= 16)&&(reinterpret_cast<const InetAddress *>(from)->ipScope() == InetAddress::IP_SCOPE_GLOBAL))
_lastDirectReceiveFromGlobal = OSUtils::now();
ZT_ResultCode rc = _node->processWirePacket(
@@ -955,7 +1059,7 @@ public:
if (from) {
ZT_ResultCode rc = _node->processWirePacket(
OSUtils::now(),
- 0,
+ &ZT_SOCKADDR_NULL,
reinterpret_cast<struct sockaddr_storage *>(&from),
data,
plen,
@@ -1164,16 +1268,23 @@ public:
}
}
- inline int nodeWirePacketSendFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len)
+ inline int nodeWirePacketSendFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
{
#ifdef ZT_USE_MINIUPNPC
if ((localAddr->ss_family == AF_INET)&&(reinterpret_cast<const struct sockaddr_in *>(localAddr)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&_v4UpnpLocalAddress)->sin_port)) {
#ifdef ZT_BREAK_UDP
if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) {
#endif
- if (addr->ss_family == AF_INET)
- return ((_phy.udpSend(_v4UpnpUdpSocket,(const struct sockaddr *)addr,data,len) != 0) ? 0 : -1);
- else return -1;
+ if (addr->ss_family == AF_INET) {
+ if (ttl)
+ _phy.setIp4UdpTtl(_v4UpnpUdpSocket,ttl);
+ const int result = ((_phy.udpSend(_v4UpnpUdpSocket,(const struct sockaddr *)addr,data,len) != 0) ? 0 : -1);
+ if (ttl)
+ _phy.setIp4UdpTtl(_v4UpnpUdpSocket,255);
+ return result;
+ } else {
+ return -1;
+ }
#ifdef ZT_BREAK_UDP
}
#endif
@@ -1186,8 +1297,13 @@ public:
#ifdef ZT_BREAK_UDP
if (!OSUtils::fileExists("/tmp/ZT_BREAK_UDP")) {
#endif
- if (_v4UdpSocket)
- result = ((_phy.udpSend(_v4UdpSocket,(const struct sockaddr *)addr,data,len) != 0) ? 0 : -1);
+ if (_v4UdpSocket) {
+ if (ttl)
+ _phy.setIp4UdpTtl(_v4UdpSocket,ttl);
+ result = ((_phy.udpSend(_v4UdpSocket,(const struct sockaddr *)addr,data,len) != 0) ? 0 : -1);
+ if (ttl)
+ _phy.setIp4UdpTtl(_v4UdpSocket,255);
+ }
#ifdef ZT_BREAK_UDP
}
#endif
@@ -1318,7 +1434,6 @@ public:
_phy.close(tc->sock); // will call close handler, which deletes from _tcpConnections
}
-private:
std::string _dataStorePrepPath(const char *name) const
{
std::string p(_homePath);
@@ -1342,7 +1457,6 @@ private:
SqliteNetworkController *_controller;
#endif
Phy<OneServiceImpl *> _phy;
- std::string _overrideRootTopology;
Node *_node;
InetAddress _v4LocalAddress,_v6LocalAddress;
PhySocket *_v4UdpSocket;
@@ -1374,6 +1488,13 @@ private:
UPNPClient *_upnpClient;
#endif
+#ifdef ZT_ENABLE_CLUSTER
+ PhySocket *_clusterMessageSocket;
+ ClusterGeoIpService *_clusterGeoIpService;
+ ClusterDefinition *_clusterDefinition;
+ unsigned int _clusterMemberId;
+#endif
+
bool _run;
Mutex _run_m;
};
@@ -1386,11 +1507,26 @@ static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name,
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeDataStoreGetFunction(name,buf,bufSize,readIndex,totalSize); }
static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure)
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeDataStorePutFunction(name,data,len,secure); }
-static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len)
-{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len); }
+static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
+{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); }
static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,sourceMac,destMac,etherType,vlanId,data,len); }
+#ifdef ZT_ENABLE_CLUSTER
+static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len)
+{
+ OneServiceImpl *const impl = reinterpret_cast<OneServiceImpl *>(uptr);
+ const ClusterDefinition::MemberDefinition &md = (*(impl->_clusterDefinition))[toMemberId];
+ if (md.clusterEndpoint)
+ impl->_phy.udpSend(impl->_clusterMessageSocket,reinterpret_cast<const struct sockaddr *>(&(md.clusterEndpoint)),data,len);
+}
+static int SclusterGeoIpFunction(void *uptr,const struct sockaddr_storage *addr,int *x,int *y,int *z)
+{
+ OneServiceImpl *const impl = reinterpret_cast<OneServiceImpl *>(uptr);
+ return (int)(impl->_clusterGeoIpService->locate(*(reinterpret_cast<const InetAddress *>(addr)),*x,*y,*z));
+}
+#endif
+
static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{ reinterpret_cast<OneServiceImpl *>(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); }
@@ -1539,7 +1675,7 @@ std::string OneService::autoUpdateUrl()
return std::string();
}
-OneService *OneService::newInstance(const char *hp,unsigned int port,const char *overrideRootTopology) { return new OneServiceImpl(hp,port,overrideRootTopology); }
+OneService *OneService::newInstance(const char *hp,unsigned int port) { return new OneServiceImpl(hp,port); }
OneService::~OneService() {}
} // namespace ZeroTier
diff --git a/service/OneService.hpp b/service/OneService.hpp
index 70d024bc..4f7b988b 100644
--- a/service/OneService.hpp
+++ b/service/OneService.hpp
@@ -43,6 +43,9 @@ namespace ZeroTier {
* periodically checked and updates are automatically downloaded, verified
* against a built-in list of update signing keys, and installed. This is
* only supported for certain platforms.
+ *
+ * If built with ZT_ENABLE_CLUSTER, a 'cluster' file is checked and if
+ * present is read to determine the identity of other cluster members.
*/
class OneService
{
@@ -95,12 +98,10 @@ public:
*
* @param hp Home path
* @param port TCP and UDP port for packets and HTTP control (if 0, pick random port)
- * @param overrideRootTopology String-serialized root topology (for testing, default: NULL)
*/
static OneService *newInstance(
const char *hp,
- unsigned int port,
- const char *overrideRootTopology = (const char *)0);
+ unsigned int port);
virtual ~OneService();
diff --git a/tests/http/2015-11-10_01_50000.out.xz b/tests/http/2015-11-10_01_50000.out.xz
new file mode 100644
index 00000000..d3e2a666
--- /dev/null
+++ b/tests/http/2015-11-10_01_50000.out.xz
Binary files differ
diff --git a/tests/http/2015-11-10_02_50000.out.xz b/tests/http/2015-11-10_02_50000.out.xz
new file mode 100644
index 00000000..0154da79
--- /dev/null
+++ b/tests/http/2015-11-10_02_50000.out.xz
Binary files differ
diff --git a/tests/http/2015-11-10_03_12500_ec2-east-only.out.xz b/tests/http/2015-11-10_03_12500_ec2-east-only.out.xz
new file mode 100644
index 00000000..3ae3555e
--- /dev/null
+++ b/tests/http/2015-11-10_03_12500_ec2-east-only.out.xz
Binary files differ
diff --git a/tests/http/Dockerfile b/tests/http/Dockerfile
new file mode 100644
index 00000000..e19b3fee
--- /dev/null
+++ b/tests/http/Dockerfile
@@ -0,0 +1,24 @@
+FROM centos:latest
+
+MAINTAINER https://www.zerotier.com/
+
+EXPOSE 9993/udp
+
+ADD nodesource-el.repo /etc/yum.repos.d/nodesource-el.repo
+RUN yum -y update && yum install -y nodejs && yum clean all
+
+RUN mkdir -p /var/lib/zerotier-one
+RUN mkdir -p /var/lib/zerotier-one/networks.d
+RUN touch /var/lib/zerotier-one/networks.d/ffffffffffffffff.conf
+
+ADD package.json /
+RUN npm install
+
+ADD zerotier-one /
+RUN chmod a+x /zerotier-one
+
+ADD agent.js /
+ADD docker-main.sh /
+RUN chmod a+x /docker-main.sh
+
+CMD ["./docker-main.sh"]
diff --git a/tests/http/README.md b/tests/http/README.md
new file mode 100644
index 00000000..23a95605
--- /dev/null
+++ b/tests/http/README.md
@@ -0,0 +1,12 @@
+HTTP one-to-all test
+======
+
+*This is really internal use code. You're free to test it out but expect to do some editing/tweaking to make it work. We used this to run some massive scale tests of our new geo-cluster-based root server infrastructure prior to taking it live.*
+
+Before using this code you will want to edit agent.js to change SERVER_HOST to the IP address of where you will run server.js. This should typically be an open Internet IP, since this makes reporting not dependent upon the thing being tested. Also note that this thing does no security of any kind. It's designed for one-off tests run over a short period of time, not to be anything that runs permanently. You will also want to edit the Dockerfile if you want to build containers and change the network ID to the network you want to run tests over.
+
+This code can be deployed across a large number of VMs or containers to test and benchmark HTTP traffic within a virtual network at scale. The agent acts as a server and can query other agents, while the server collects agent data and tells agents about each other. It's designed to use RFC4193-based ZeroTier IPv6 addresses within the cluster, which allows the easy provisioning of a large cluster without IP conflicts.
+
+The Dockerfile builds an image that launches the agent. The image must be "docker run" with "--device=/dev/net/tun --privileged" to permit it to open a tun/tap device within the container. (Unfortunately CAP_NET_ADMIN may not work due to a bug in Docker and/or Linux.) You can run a bunch with a command like:
+
+ for ((n=0;n<10;n++)); do docker run --device=/dev/net/tun --privileged -d zerotier/http-test; done
diff --git a/tests/http/agent.js b/tests/http/agent.js
new file mode 100644
index 00000000..9ab2e019
--- /dev/null
+++ b/tests/http/agent.js
@@ -0,0 +1,196 @@
+// ZeroTier distributed HTTP test agent
+
+// ---------------------------------------------------------------------------
+// Customizable parameters:
+
+// Time between startup and first test attempt
+var TEST_STARTUP_LAG = 10000;
+
+// Maximum interval between test attempts (actual timing is random % this)
+var TEST_INTERVAL_MAX = (60000 * 10);
+
+// Test timeout in ms
+var TEST_TIMEOUT = 30000;
+
+// Where should I get other agents' IDs and POST results?
+var SERVER_HOST = '52.26.196.147';
+var SERVER_PORT = 18080;
+
+// Which port do agents use to serve up test data to each other?
+var AGENT_PORT = 18888;
+
+// Payload size in bytes
+var PAYLOAD_SIZE = 5000;
+
+// ---------------------------------------------------------------------------
+
+var ipaddr = require('ipaddr.js');
+var os = require('os');
+var http = require('http');
+var async = require('async');
+
+var express = require('express');
+var app = express();
+
+// Find our ZeroTier-assigned RFC4193 IPv6 address
+var thisAgentId = null;
+var interfaces = os.networkInterfaces();
+if (!interfaces) {
+ console.error('FATAL: os.networkInterfaces() failed.');
+ process.exit(1);
+}
+for(var ifname in interfaces) {
+ var ifaddrs = interfaces[ifname];
+ if (Array.isArray(ifaddrs)) {
+ for(var i=0;i<ifaddrs.length;++i) {
+ if (ifaddrs[i].family == 'IPv6') {
+ try {
+ var ipbytes = ipaddr.parse(ifaddrs[i].address).toByteArray();
+ if ((ipbytes.length === 16)&&(ipbytes[0] == 0xfd)&&(ipbytes[9] == 0x99)&&(ipbytes[10] == 0x93)) {
+ thisAgentId = '';
+ for(var j=0;j<16;++j) {
+ var tmp = ipbytes[j].toString(16);
+ if (tmp.length === 1)
+ thisAgentId += '0';
+ thisAgentId += tmp;
+ }
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }
+ }
+}
+if (thisAgentId === null) {
+ console.error('FATAL: no ZeroTier-assigned RFC4193 IPv6 addresses found on any local interface!');
+ process.exit(1);
+}
+
+//console.log(thisAgentId);
+
+// Create a random (and therefore not very compressable) payload
+var payload = new Buffer(PAYLOAD_SIZE);
+for(var xx=0;xx<PAYLOAD_SIZE;++xx) {
+ payload.writeUInt8(Math.round(Math.random() * 255.0),xx);
+}
+
+function agentIdToIp(agentId)
+{
+ var ip = '';
+ ip += agentId.substr(0,4);
+ ip += ':';
+ ip += agentId.substr(4,4);
+ ip += ':';
+ ip += agentId.substr(8,4);
+ ip += ':';
+ ip += agentId.substr(12,4);
+ ip += ':';
+ ip += agentId.substr(16,4);
+ ip += ':';
+ ip += agentId.substr(20,4);
+ ip += ':';
+ ip += agentId.substr(24,4);
+ ip += ':';
+ ip += agentId.substr(28,4);
+ return ip;
+};
+
+var lastTestResult = null;
+var allOtherAgents = {};
+
+function doTest()
+{
+ var submit = http.request({
+ host: SERVER_HOST,
+ port: SERVER_PORT,
+ path: '/'+thisAgentId,
+ method: 'POST'
+ },function(res) {
+ var body = '';
+ res.on('data',function(chunk) { body += chunk.toString(); });
+ res.on('end',function() {
+
+ if (body) {
+ try {
+ var peers = JSON.parse(body);
+ if (Array.isArray(peers)) {
+ for(var xx=0;xx<peers.length;++xx)
+ allOtherAgents[peers[xx]] = true;
+ }
+ } catch (e) {}
+ }
+
+ var agents = Object.keys(allOtherAgents);
+ if (agents.length > 1) {
+
+ var target = agents[Math.floor(Math.random() * agents.length)];
+ while (target === thisAgentId)
+ target = agents[Math.floor(Math.random() * agents.length)];
+
+ var testRequest = null;
+ var timeoutId = null;
+ timeoutId = setTimeout(function() {
+ if (testRequest !== null)
+ testRequest.abort();
+ timeoutId = null;
+ },TEST_TIMEOUT);
+ var startTime = Date.now();
+
+ testRequest = http.get({
+ host: agentIdToIp(target),
+ port: AGENT_PORT,
+ path: '/'
+ },function(res) {
+ var bytes = 0;
+ res.on('data',function(chunk) { bytes += chunk.length; });
+ res.on('end',function() {
+ lastTestResult = {
+ source: thisAgentId,
+ target: target,
+ time: (Date.now() - startTime),
+ bytes: bytes,
+ timedOut: (timeoutId === null),
+ error: null
+ };
+ if (timeoutId !== null)
+ clearTimeout(timeoutId);
+ return setTimeout(doTest,Math.round(Math.random() * TEST_INTERVAL_MAX) + 1);
+ });
+ }).on('error',function(e) {
+ lastTestResult = {
+ source: thisAgentId,
+ target: target,
+ time: (Date.now() - startTime),
+ bytes: 0,
+ timedOut: (timeoutId === null),
+ error: e.toString()
+ };
+ if (timeoutId !== null)
+ clearTimeout(timeoutId);
+ return setTimeout(doTest,Math.round(Math.random() * TEST_INTERVAL_MAX) + 1);
+ });
+
+ } else {
+ return setTimeout(doTest,1000);
+ }
+
+ });
+ }).on('error',function(e) {
+ console.log('POST failed: '+e.toString());
+ return setTimeout(doTest,1000);
+ });
+ if (lastTestResult !== null) {
+ submit.write(JSON.stringify(lastTestResult));
+ lastTestResult = null;
+ }
+ submit.end();
+};
+
+// Agents just serve up a test payload
+app.get('/',function(req,res) { return res.status(200).send(payload); });
+
+var expressServer = app.listen(AGENT_PORT,function () {
+ // Start timeout-based loop
+ setTimeout(doTest(),TEST_STARTUP_LAG);
+});
diff --git a/tests/http/big-test-kill.sh b/tests/http/big-test-kill.sh
new file mode 100755
index 00000000..fa7f3cc4
--- /dev/null
+++ b/tests/http/big-test-kill.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# Kills all running Docker containers on all big-test-hosts
+
+export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin
+
+pssh -h big-test-hosts -x '-t -t' -i -OUserKnownHostsFile=/dev/null -OStrictHostKeyChecking=no -t 0 -p 256 "sudo docker ps -aq | xargs -r sudo docker rm -f"
+
+exit 0
diff --git a/tests/http/big-test-start.sh b/tests/http/big-test-start.sh
new file mode 100755
index 00000000..2411eeda
--- /dev/null
+++ b/tests/http/big-test-start.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# More than 500 container seems to result in a lot of sporadic failures, probably due to Linux kernel scaling issues with virtual network ports
+# 250 with a 16GB RAM VM like Amazon m4.xlarge seems good
+NUM_CONTAINERS=250
+CONTAINER_IMAGE=zerotier/http-test
+SCALE_UP_DELAY=10
+
+export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin
+
+pssh -h big-test-hosts -x '-t -t' -i -OUserKnownHostsFile=/dev/null -OStrictHostKeyChecking=no -t 0 -p 256 "sudo sysctl -w net.netfilter.nf_conntrack_max=262144 ; for ((n=0;n<$NUM_CONTAINERS;n++)); do sudo docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE; sleep $SCALE_UP_DELAY; done"
+
+exit 0
diff --git a/tests/http/crunch-results.js b/tests/http/crunch-results.js
new file mode 100644
index 00000000..50e5c49a
--- /dev/null
+++ b/tests/http/crunch-results.js
@@ -0,0 +1,65 @@
+//
+// Pipe the output of server.js into this to convert raw test results into bracketed statistics
+// suitable for graphing.
+//
+
+// Time duration per statistical bracket
+var BRACKET_SIZE = 10000;
+
+// Number of bytes expected from each test
+var EXPECTED_BYTES = 5000;
+
+var readline = require('readline');
+var rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ terminal: false
+});
+
+var count = 0.0;
+var overallCount = 0.0;
+var totalFailures = 0.0;
+var totalOverallFailures = 0.0;
+var totalMs = 0;
+var totalData = 0;
+var devices = {};
+var lastBracketTs = 0;
+
+rl.on('line',function(line) {
+ line = line.trim();
+ var ls = line.split(',');
+ if (ls.length == 7) {
+ var ts = parseInt(ls[0]);
+ var fromId = ls[1];
+ var toId = ls[2];
+ var ms = parseFloat(ls[3]);
+ var bytes = parseInt(ls[4]);
+ var timedOut = (ls[5] == 'true') ? true : false;
+ var errMsg = ls[6];
+
+ count += 1.0;
+ overallCount += 1.0;
+ if ((bytes !== EXPECTED_BYTES)||(timedOut)) {
+ totalFailures += 1.0;
+ totalOverallFailures += 1.0;
+ }
+ totalMs += ms;
+ totalData += bytes;
+
+ devices[fromId] = true;
+ devices[toId] = true;
+
+ if (lastBracketTs === 0)
+ lastBracketTs = ts;
+
+ if (((ts - lastBracketTs) >= BRACKET_SIZE)&&(count > 0.0)) {
+ console.log(count.toString()+','+overallCount.toString()+','+(totalMs / count)+','+(totalFailures / count)+','+(totalOverallFailures / overallCount)+','+totalData+','+Object.keys(devices).length);
+
+ count = 0.0;
+ totalFailures = 0.0;
+ totalMs = 0;
+ totalData = 0;
+ lastBracketTs = ts;
+ }
+ } // else ignore junk
+});
diff --git a/tests/http/docker-main.sh b/tests/http/docker-main.sh
new file mode 100755
index 00000000..29cdced9
--- /dev/null
+++ b/tests/http/docker-main.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin
+
+/zerotier-one -d >>zerotier-one.out 2>&1
+
+# Wait for ZeroTier to start and join the network
+while [ ! -d "/proc/sys/net/ipv6/conf/zt0" ]; do
+ sleep 0.25
+done
+
+# Wait just a bit longer for stuff to settle
+sleep 5
+
+exec node --harmony /agent.js >>agent.out 2>&1
+#exec node --harmony /agent.js
diff --git a/tests/http/nodesource-el.repo b/tests/http/nodesource-el.repo
new file mode 100644
index 00000000..b785d3d0
--- /dev/null
+++ b/tests/http/nodesource-el.repo
@@ -0,0 +1,6 @@
+[nodesource]
+name=Node.js Packages for Enterprise Linux 7 - $basearch
+baseurl=https://rpm.nodesource.com/pub_4.x/el/7/$basearch
+failovermethod=priority
+enabled=1
+gpgcheck=0
diff --git a/tests/http/package.json b/tests/http/package.json
new file mode 100644
index 00000000..173a6f99
--- /dev/null
+++ b/tests/http/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "zerotier-test-http",
+ "version": "1.0.0",
+ "description": "ZeroTier in-network HTTP test",
+ "main": "agent.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "ZeroTier, Inc.",
+ "license": "GPL-3.0",
+ "dependencies": {
+ "async": "^1.5.0",
+ "express": "^4.13.3",
+ "ipaddr.js": "^1.0.3"
+ }
+}
diff --git a/tests/http/server.js b/tests/http/server.js
new file mode 100644
index 00000000..629784da
--- /dev/null
+++ b/tests/http/server.js
@@ -0,0 +1,53 @@
+// ZeroTier distributed HTTP test coordinator and result-reporting server
+
+// ---------------------------------------------------------------------------
+// Customizable parameters:
+
+var SERVER_PORT = 18080;
+
+// ---------------------------------------------------------------------------
+
+var fs = require('fs');
+
+var express = require('express');
+var app = express();
+
+app.use(function(req,res,next) {
+ req.rawBody = '';
+ req.on('data', function(chunk) { req.rawBody += chunk.toString(); });
+ req.on('end', function() { return next(); });
+});
+
+var knownAgents = {};
+
+app.post('/:agentId',function(req,res) {
+ var agentId = req.params.agentId;
+ if ((!agentId)||(agentId.length !== 32))
+ return res.status(404).send('');
+
+ if (req.rawBody) {
+ var receiveTime = Date.now();
+ var resultData = null;
+ try {
+ resultData = JSON.parse(req.rawBody);
+ console.log(Date.now().toString()+','+resultData.source+','+resultData.target+','+resultData.time+','+resultData.bytes+','+resultData.timedOut+',"'+((resultData.error) ? resultData.error : '')+'"');
+ } catch (e) {}
+ }
+
+ knownAgents[agentId] = true;
+ var thisUpdate = [];
+ var agents = Object.keys(knownAgents);
+ if (agents.length < 100)
+ thisUpdate = agents;
+ else {
+ for(var xx=0;xx<100;++xx)
+ thisUpdate.push(agents[Math.floor(Math.random() * agents.length)]);
+ }
+
+ return res.status(200).send(JSON.stringify(thisUpdate));
+});
+
+var expressServer = app.listen(SERVER_PORT,function () {
+ console.log('LISTENING ON '+SERVER_PORT);
+ console.log('');
+});
diff --git a/ui/ZeroTierNetwork.jsx b/ui/ZeroTierNetwork.jsx
index 4b37d888..f842d758 100644
--- a/ui/ZeroTierNetwork.jsx
+++ b/ui/ZeroTierNetwork.jsx
@@ -4,19 +4,17 @@ var ZeroTierNetwork = React.createClass({
},
leaveNetwork: function(event) {
- if (confirm("Are you sure you want to leave this network?")) {
- Ajax.call({
- url: 'network/'+this.props.nwid+'?auth='+this.props.authToken,
- cache: false,
- type: 'DELETE',
- success: function(data) {
- if (this.props.onNetworkDeleted)
- this.props.onNetworkDeleted(this.props.nwid);
- }.bind(this),
- error: function(error) {
- }.bind(this)
- });
- }
+ Ajax.call({
+ url: 'network/'+this.props.nwid+'?auth='+this.props.authToken,
+ cache: false,
+ type: 'DELETE',
+ success: function(data) {
+ if (this.props.onNetworkDeleted)
+ this.props.onNetworkDeleted(this.props.nwid);
+ }.bind(this),
+ error: function(error) {
+ }.bind(this)
+ });
event.preventDefault();
},
diff --git a/ui/ZeroTierNode.jsx b/ui/ZeroTierNode.jsx
index 49d73460..b4c29220 100644
--- a/ui/ZeroTierNode.jsx
+++ b/ui/ZeroTierNode.jsx
@@ -122,7 +122,6 @@ var ZeroTierNode = React.createClass({
},
componentDidMount: function() {
- this.tabIndex = 0;
this.updateAll();
this.updateIntervalId = setInterval(this.updateAll,2500);
},
@@ -130,74 +129,19 @@ var ZeroTierNode = React.createClass({
clearInterval(this.updateIntervalId);
},
render: function() {
- /* We implement tabs in a very simple way here with a React JSX conditional. The tabIndex
- * local variable indicates the tab, and switching it determines which set of things we
- * render in the main middle portion. On tab switch calls forceUpdate(). */
return (
<div className="zeroTierNode">
- <div className="top">&nbsp;&nbsp;
- <button disabled={this.tabIndex === 0} onClick={function() {this.tabIndex = 0; this.forceUpdate();}.bind(this)}>Networks</button>
- <button disabled={this.tabIndex === 1} onClick={function() {this.tabIndex = 1; this.forceUpdate();}.bind(this)}>Peers</button>
- </div>
<div className="middle"><div className="middleCell">
<div className="middleScroll">
- {
- (this.tabIndex === 1) ? (
- <div className="peers" key="_peers">
- <div className="peerHeader" key="_peersHeader">
- <div className="f">Address</div>
- <div className="f">Version</div>
- <div className="f">Latency</div>
- <div className="f">Data&nbsp;Paths</div>
- <div className="f">Last&nbsp;Unicast</div>
- <div className="f">Last&nbsp;Multicast</div>
- <div className="f">Role</div>
- </div>
- {
- this.state._peers.map(function(peer) {
- return (
- <div className="peer" key={peer['address']}>
- <div className="f zeroTierAddress">{peer['address']}</div>
- <div className="f">{(peer['version'] === '-1.-1.-1') ? '-' : peer['version']}</div>
- <div className="f">{peer['latency']}</div>
- <div className="f">
- {
- (peer['paths'].length === 0) ? (
- <div className="peerPath"></div>
- ) : (
- <div>
- {
- peer['paths'].map(function(path) {
- var cn = ((path.active)||(path.fixed)) ? (path.preferred ? 'peerPathPreferred' : 'peerPathActive') : 'peerPathInactive';
- return (
- <div className={cn}>{path.address}&nbsp;&nbsp;{this.ago(path.lastSend)}/{this.ago(path.lastReceive)}</div>
- );
- }.bind(this))
- }
- </div>
- )
- }
- </div>
- <div className="f">{this.ago(peer['lastUnicastFrame'])}</div>
- <div className="f">{this.ago(peer['lastMulticastFrame'])}</div>
- <div className="f">{peer['role']}</div>
- </div>
- );
- }.bind(this))
- }
- </div>
- ) : (
- <div className="networks" key="_networks">
- {
- this.state._networks.map(function(network) {
- network['authToken'] = this.props.authToken;
- network['onNetworkDeleted'] = this.handleNetworkDelete;
- return React.createElement('div',{className: 'network',key: network.nwid},React.createElement(ZeroTierNetwork,network));
- }.bind(this))
- }
- </div>
- )
- }
+ <div className="networks" key="_networks">
+ {
+ this.state._networks.map(function(network) {
+ network['authToken'] = this.props.authToken;
+ network['onNetworkDeleted'] = this.handleNetworkDelete;
+ return React.createElement('div',{className: 'network',key: network.nwid},React.createElement(ZeroTierNetwork,network));
+ }.bind(this))
+ }
+ </div>
</div>
</div></div>
<div className="bottom">
diff --git a/ui/zerotier.css b/ui/zerotier.css
index cde5cea8..9f72024a 100644
--- a/ui/zerotier.css
+++ b/ui/zerotier.css
@@ -25,34 +25,6 @@ html,body {
display: table;
}
-.zeroTierNode > .top {
- width: 100%;
- overflow: hidden;
- display: table-row;
- white-space: nowrap;
- background: #234447;
- color: #ffffff;
- padding: 0;
- margin: 0;
-}
-.zeroTierNode > .top button {
- display: inline-block;
- padding: 0.25rem 0.75rem 0.25rem 0.75rem;
- color: #ffffff;
- margin: 0;
- border: 0;
- outline: none;
- background: #234447;
- font-size: 12pt;
- cursor: pointer;
-}
-.zeroTierNode > .top button:hover {
- background: #91a2a3;
-}
-.zeroTierNode > .top button:disabled {
- background: #91a2a3;
-}
-
.zeroTierNode > .middle {
width: 100%;
height: 100%;
@@ -65,6 +37,7 @@ html,body {
width: 100%;
height: 100%;
display: table-cell;
+ border-bottom: 1px solid #cfcfcf;
}
.zeroTierNode > .middle > .middleCell > .middleScroll {
display: block;
@@ -87,77 +60,20 @@ html,body {
border-collapse: collapse;
}
.zeroTierNode > .middle > .middleCell > .middleScroll > .networks > .network {
- display: inline-block;
+ display: block;
+ border-top: 0.12rem solid #dddddd;
+ border-bottom: 0.12rem solid #dddddd;
padding: 0.25rem;
- margin: 0.25rem 0 0 1%;
- min-width: 31%;
- max-width: 98%;
- border: 1px solid #234447;
background: #ffffff;
}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers {
- display: table;
- width: 100%;
- margin: 0;
- border-collapse: collapse;
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peer {
- width: 100%;
- display: table-row;
- background: #ffffff;
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peer:nth-child(odd) {
- background: #f3f3f3;
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peer:nth-child(even) {
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peer .peerPathActive {
- font-size: 8pt;
- color: #555555;
- font-style: italic;
- font-family: monospace;
- white-space: nowrap;
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peer .peerPathPreferred {
- font-size: 8pt;
- color: #000000;
- font-family: monospace;
- white-space: nowrap;
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peer .peerPathInactive {
- font-size: 8pt;
- font-family: monospace;
- color: #aaaaaa;
- font-style: italic;
- text-decoration: line-through;
- white-space: nowrap;
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peer > .f {
- display: table-cell;
- padding: 0.05rem 0.15rem 0.05rem 0.15rem;
- font-size: 8pt;
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peerHeader {
- width: 100%;
- font-size: 8pt;
- display: table-row;
- background: #ffffff;
- border-bottom: 1px solid #000000;
-}
-.zeroTierNode > .middle > .middleCell > .middleScroll > .peers > .peerHeader > .f {
- display: table-cell;
- font-size: 8pt;
- padding: 0.05rem 0.15rem 0.05rem 0.15rem;
- font-weight: bold;
-}
.zeroTierNode > .bottom {
font-size: 12pt;
width: 100%;
overflow: hidden;
display: table-row;
- background: #234447;
- color: #ffffff;
+ color: #000000;
+ background: #dfdfdf;
}
.zeroTierNode > .bottom > .left {
text-align: left;
@@ -233,7 +149,7 @@ html,body {
.zeroTierNetwork .networkInfo .networkId {
font-size: 11pt;
font-family: monospace;
- color: #91a2a3;
+ color: #000000;
}
.zeroTierNetwork .networkInfo .networkName {
padding: 0 0 0 1rem;
@@ -271,7 +187,7 @@ html,body {
.zeroTierNetwork .leaveNetworkButton {
padding: 0.25rem 0.5rem 0.25rem 0.5rem;
margin: 0.25rem 0 0 0;
- font-size: 10pt;
+ font-size: 9pt;
background: #ffffff;
outline: none;
background: #ffb354;
diff --git a/ui/ztui.min.js b/ui/ztui.min.js
index dbde7734..17982839 100644
--- a/ui/ztui.min.js
+++ b/ui/ztui.min.js
@@ -1 +1 @@
-var ZeroTierNetwork=React.createClass({displayName:"ZeroTierNetwork",getInitialState:function(){return{}},leaveNetwork:function(e){confirm("Are you sure you want to leave this network?")&&Ajax.call({url:"network/"+this.props.nwid+"?auth="+this.props.authToken,cache:!1,type:"DELETE",success:function(e){this.props.onNetworkDeleted&&this.props.onNetworkDeleted(this.props.nwid)}.bind(this),error:function(e){}.bind(this)}),e.preventDefault()},render:function(){return React.createElement("div",{className:"zeroTierNetwork"},React.createElement("div",{className:"networkInfo"},React.createElement("span",{className:"networkId"},this.props.nwid)," ",React.createElement("span",{className:"networkName"},this.props.name)),React.createElement("div",{className:"networkProps"},React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Status"),React.createElement("div",{className:"value"},this.props.status)),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Type"),React.createElement("div",{className:"value"},this.props.type)),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"MAC"),React.createElement("div",{className:"value zeroTierAddress"},this.props.mac)),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"MTU"),React.createElement("div",{className:"value"},this.props.mtu)),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Broadcast"),React.createElement("div",{className:"value"},this.props.broadcastEnabled?"ENABLED":"DISABLED")),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Bridging"),React.createElement("div",{className:"value"},this.props.bridge?"ACTIVE":"DISABLED")),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Device"),React.createElement("div",{className:"value"},this.props.portDeviceName?this.props.portDeviceName:"(none)")),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Managed IPs"),React.createElement("div",{className:"value ipList"},this.props.assignedAddresses.map(function(e){return React.createElement("div",{key:e,className:"ipAddress"},e)})))),React.createElement("button",{type:"button",className:"leaveNetworkButton",onClick:this.leaveNetwork},"Leave Network"))}}); var ZeroTierNode=React.createClass({displayName:"ZeroTierNode",getInitialState:function(){return{address:"----------",online:!1,version:"_._._",_networks:[],_peers:[]}},ago:function(e){if(e>0){var t=Math.round((Date.now()-e)/1e3);return t>0?t:0}return 0},updatePeers:function(){Ajax.call({url:"peer?auth="+this.props.authToken,cache:!1,type:"GET",success:function(e){if(e){var t=JSON.parse(e);Array.isArray(t)&&this.setState({_peers:t})}}.bind(this),error:function(){}.bind(this)})},updateNetworks:function(){Ajax.call({url:"network?auth="+this.props.authToken,cache:!1,type:"GET",success:function(e){if(e){var t=JSON.parse(e);Array.isArray(t)&&this.setState({_networks:t})}}.bind(this),error:function(){}.bind(this)})},updateAll:function(){Ajax.call({url:"status?auth="+this.props.authToken,cache:!1,type:"GET",success:function(e){if(this.alertedToFailure=!1,e){var t=JSON.parse(e);this.setState(t),document.title="ZeroTier One ["+t.address+"]"}this.updateNetworks(),this.updatePeers()}.bind(this),error:function(){this.setState(this.getInitialState()),this.alertedToFailure||(this.alertedToFailure=!0,alert("Authorization token invalid or ZeroTier One service not running."))}.bind(this)})},joinNetwork:function(e){e.preventDefault(),this.networkToJoin&&16===this.networkToJoin.length?Ajax.call({url:"network/"+this.networkToJoin+"?auth="+this.props.authToken,cache:!1,type:"POST",success:function(e){this.networkToJoin="",this.networkInputElement&&(this.networkInputElement.value=""),this.updateNetworks()}.bind(this),error:function(){}.bind(this)}):alert("To join a network, enter its 16-digit network ID.")},handleNetworkIdEntry:function(e){this.networkInputElement=e.target;var t=this.networkInputElement.value;if(t){t=t.toLowerCase();for(var a="",s=0;s<t.length&&16>s;++s)"0123456789abcdef".indexOf(t.charAt(s))>=0&&(a+=t.charAt(s));this.networkToJoin=a,this.networkInputElement.value=a}else this.networkToJoin="",this.networkInputElement.value=""},handleNetworkDelete:function(e){for(var t=[],a=0;a<this.state._networks.length;++a)this.state._networks[a].nwid!==e&&t.push(this.state._networks[a]);this.setState({_networks:t})},componentDidMount:function(){this.tabIndex=0,this.updateAll(),this.updateIntervalId=setInterval(this.updateAll,2500)},componentWillUnmount:function(){clearInterval(this.updateIntervalId)},render:function(){return React.createElement("div",{className:"zeroTierNode"},React.createElement("div",{className:"top"},"  ",React.createElement("button",{disabled:0===this.tabIndex,onClick:function(){this.tabIndex=0,this.forceUpdate()}.bind(this)},"Networks"),React.createElement("button",{disabled:1===this.tabIndex,onClick:function(){this.tabIndex=1,this.forceUpdate()}.bind(this)},"Peers")),React.createElement("div",{className:"middle"},React.createElement("div",{className:"middleCell"},React.createElement("div",{className:"middleScroll"},1===this.tabIndex?React.createElement("div",{className:"peers",key:"_peers"},React.createElement("div",{className:"peerHeader",key:"_peersHeader"},React.createElement("div",{className:"f"},"Address"),React.createElement("div",{className:"f"},"Version"),React.createElement("div",{className:"f"},"Latency"),React.createElement("div",{className:"f"},"Data Paths"),React.createElement("div",{className:"f"},"Last Unicast"),React.createElement("div",{className:"f"},"Last Multicast"),React.createElement("div",{className:"f"},"Role")),this.state._peers.map(function(e){return React.createElement("div",{className:"peer",key:e.address},React.createElement("div",{className:"f zeroTierAddress"},e.address),React.createElement("div",{className:"f"},"-1.-1.-1"===e.version?"-":e.version),React.createElement("div",{className:"f"},e.latency),React.createElement("div",{className:"f"},0===e.paths.length?React.createElement("div",{className:"peerPath"}):React.createElement("div",null,e.paths.map(function(e){var t=e.active||e.fixed?e.preferred?"peerPathPreferred":"peerPathActive":"peerPathInactive";return React.createElement("div",{className:t},e.address,"  ",this.ago(e.lastSend),"/",this.ago(e.lastReceive))}.bind(this)))),React.createElement("div",{className:"f"},this.ago(e.lastUnicastFrame)),React.createElement("div",{className:"f"},this.ago(e.lastMulticastFrame)),React.createElement("div",{className:"f"},e.role))}.bind(this))):React.createElement("div",{className:"networks",key:"_networks"},this.state._networks.map(function(e){return e.authToken=this.props.authToken,e.onNetworkDeleted=this.handleNetworkDelete,React.createElement("div",{className:"network",key:e.nwid},React.createElement(ZeroTierNetwork,e))}.bind(this)))))),React.createElement("div",{className:"bottom"},React.createElement("div",{className:"left"},React.createElement("span",{className:"statusLine"},React.createElement("span",{className:"zeroTierAddress"},this.state.address),"  ",this.state.online?this.state.tcpFallbackActive?"TUNNELED":"ONLINE":"OFFLINE","  ",this.state.version)),React.createElement("div",{className:"right"},React.createElement("form",{onSubmit:this.joinNetwork},React.createElement("input",{type:"text",maxlength:"16",placeholder:"[ Network ID ]",onChange:this.handleNetworkIdEntry,size:"16"}),React.createElement("button",{type:"button",onClick:this.joinNetwork},"Join")))))}});
+var ZeroTierNetwork=React.createClass({displayName:"ZeroTierNetwork",getInitialState:function(){return{}},leaveNetwork:function(e){Ajax.call({url:"network/"+this.props.nwid+"?auth="+this.props.authToken,cache:!1,type:"DELETE",success:function(e){this.props.onNetworkDeleted&&this.props.onNetworkDeleted(this.props.nwid)}.bind(this),error:function(e){}.bind(this)}),e.preventDefault()},render:function(){return React.createElement("div",{className:"zeroTierNetwork"},React.createElement("div",{className:"networkInfo"},React.createElement("span",{className:"networkId"},this.props.nwid)," ",React.createElement("span",{className:"networkName"},this.props.name)),React.createElement("div",{className:"networkProps"},React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Status"),React.createElement("div",{className:"value"},this.props.status)),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Type"),React.createElement("div",{className:"value"},this.props.type)),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"MAC"),React.createElement("div",{className:"value zeroTierAddress"},this.props.mac)),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"MTU"),React.createElement("div",{className:"value"},this.props.mtu)),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Broadcast"),React.createElement("div",{className:"value"},this.props.broadcastEnabled?"ENABLED":"DISABLED")),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Bridging"),React.createElement("div",{className:"value"},this.props.bridge?"ACTIVE":"DISABLED")),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Device"),React.createElement("div",{className:"value"},this.props.portDeviceName?this.props.portDeviceName:"(none)")),React.createElement("div",{className:"row"},React.createElement("div",{className:"name"},"Managed IPs"),React.createElement("div",{className:"value ipList"},this.props.assignedAddresses.map(function(e){return React.createElement("div",{key:e,className:"ipAddress"},e)})))),React.createElement("button",{type:"button",className:"leaveNetworkButton",onClick:this.leaveNetwork},"Leave Network"))}}); var ZeroTierNode=React.createClass({displayName:"ZeroTierNode",getInitialState:function(){return{address:"----------",online:!1,version:"_._._",_networks:[],_peers:[]}},ago:function(e){if(e>0){var t=Math.round((Date.now()-e)/1e3);return t>0?t:0}return 0},updatePeers:function(){Ajax.call({url:"peer?auth="+this.props.authToken,cache:!1,type:"GET",success:function(e){if(e){var t=JSON.parse(e);Array.isArray(t)&&this.setState({_peers:t})}}.bind(this),error:function(){}.bind(this)})},updateNetworks:function(){Ajax.call({url:"network?auth="+this.props.authToken,cache:!1,type:"GET",success:function(e){if(e){var t=JSON.parse(e);Array.isArray(t)&&this.setState({_networks:t})}}.bind(this),error:function(){}.bind(this)})},updateAll:function(){Ajax.call({url:"status?auth="+this.props.authToken,cache:!1,type:"GET",success:function(e){if(this.alertedToFailure=!1,e){var t=JSON.parse(e);this.setState(t),document.title="ZeroTier One ["+t.address+"]"}this.updateNetworks(),this.updatePeers()}.bind(this),error:function(){this.setState(this.getInitialState()),this.alertedToFailure||(this.alertedToFailure=!0,alert("Authorization token invalid or ZeroTier One service not running."))}.bind(this)})},joinNetwork:function(e){e.preventDefault(),this.networkToJoin&&16===this.networkToJoin.length?Ajax.call({url:"network/"+this.networkToJoin+"?auth="+this.props.authToken,cache:!1,type:"POST",success:function(e){this.networkToJoin="",this.networkInputElement&&(this.networkInputElement.value=""),this.updateNetworks()}.bind(this),error:function(){}.bind(this)}):alert("To join a network, enter its 16-digit network ID.")},handleNetworkIdEntry:function(e){this.networkInputElement=e.target;var t=this.networkInputElement.value;if(t){t=t.toLowerCase();for(var n="",a=0;a<t.length&&16>a;++a)"0123456789abcdef".indexOf(t.charAt(a))>=0&&(n+=t.charAt(a));this.networkToJoin=n,this.networkInputElement.value=n}else this.networkToJoin="",this.networkInputElement.value=""},handleNetworkDelete:function(e){for(var t=[],n=0;n<this.state._networks.length;++n)this.state._networks[n].nwid!==e&&t.push(this.state._networks[n]);this.setState({_networks:t})},componentDidMount:function(){this.updateAll(),this.updateIntervalId=setInterval(this.updateAll,2500)},componentWillUnmount:function(){clearInterval(this.updateIntervalId)},render:function(){return React.createElement("div",{className:"zeroTierNode"},React.createElement("div",{className:"middle"},React.createElement("div",{className:"middleCell"},React.createElement("div",{className:"middleScroll"},React.createElement("div",{className:"networks",key:"_networks"},this.state._networks.map(function(e){return e.authToken=this.props.authToken,e.onNetworkDeleted=this.handleNetworkDelete,React.createElement("div",{className:"network",key:e.nwid},React.createElement(ZeroTierNetwork,e))}.bind(this)))))),React.createElement("div",{className:"bottom"},React.createElement("div",{className:"left"},React.createElement("span",{className:"statusLine"},React.createElement("span",{className:"zeroTierAddress"},this.state.address),"  ",this.state.online?this.state.tcpFallbackActive?"TUNNELED":"ONLINE":"OFFLINE","  ",this.state.version)),React.createElement("div",{className:"right"},React.createElement("form",{onSubmit:this.joinNetwork},React.createElement("input",{type:"text",maxlength:"16",placeholder:"[ Network ID ]",onChange:this.handleNetworkIdEntry,size:"16"}),React.createElement("button",{type:"button",onClick:this.joinNetwork},"Join")))))}});
diff --git a/version.h b/version.h
index 4c36cb5e..e2773877 100644
--- a/version.h
+++ b/version.h
@@ -36,11 +36,11 @@
/**
* Minor version
*/
-#define ZEROTIER_ONE_VERSION_MINOR 0
+#define ZEROTIER_ONE_VERSION_MINOR 1
/**
* Revision
*/
-#define ZEROTIER_ONE_VERSION_REVISION 6
+#define ZEROTIER_ONE_VERSION_REVISION 0
#endif
diff --git a/windows/TapDriver/TapDriver.vcxproj b/windows/TapDriver/TapDriver.vcxproj
deleted file mode 100644
index 787cc68f..00000000
--- a/windows/TapDriver/TapDriver.vcxproj
+++ /dev/null
@@ -1,385 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Win8 Debug|Win32">
- <Configuration>Win8 Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Win8 Release|Win32">
- <Configuration>Win8 Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Win7 Debug|Win32">
- <Configuration>Win7 Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Win7 Release|Win32">
- <Configuration>Win7 Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Vista Debug|Win32">
- <Configuration>Vista Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Vista Release|Win32">
- <Configuration>Vista Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Win8 Debug|x64">
- <Configuration>Win8 Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Win8 Release|x64">
- <Configuration>Win8 Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Win7 Debug|x64">
- <Configuration>Win7 Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Win7 Release|x64">
- <Configuration>Win7 Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Vista Debug|x64">
- <Configuration>Vista Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Vista Release|x64">
- <Configuration>Vista Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <ProjectGuid>{689210B1-467C-4850-BB7D-2E10D5B4A3DA}</ProjectGuid>
- <TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
- <Configuration>Win8 Debug</Configuration>
- <Platform Condition="'$(Platform)' == ''">Win32</Platform>
- </PropertyGroup>
- <PropertyGroup Label="Globals">
- <RootNamespace>TapDriver</RootNamespace>
- <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VisualStudioVersion)' == '11.0'">$(VCTargetsPath11)</VCTargetsPath>
- </PropertyGroup>
- <PropertyGroup Label="PropertySheets">
- <PlatformToolset>WindowsKernelModeDriver8.0</PlatformToolset>
- <ConfigurationType>Driver</ConfigurationType>
- <DriverType>KMDF</DriverType>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'" Label="Configuration">
- <TargetVersion>Windows8</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'" Label="Configuration">
- <TargetVersion>Windows8</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'" Label="Configuration">
- <TargetVersion>Windows7</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'" Label="Configuration">
- <TargetVersion>Windows7</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'" Label="Configuration">
- <TargetVersion>Vista</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'" Label="Configuration">
- <TargetVersion>Vista</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'" Label="Configuration">
- <TargetVersion>Windows8</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'" Label="Configuration">
- <TargetVersion>Windows8</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'" Label="Configuration">
- <TargetVersion>Windows7</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'" Label="Configuration">
- <TargetVersion>Windows7</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'" Label="Configuration">
- <TargetVersion>Vista</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'" Label="Configuration">
- <TargetVersion>Vista</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <IntDir>$(Platform)\$(ConfigurationName)\</IntDir>
- <TimeStampServer>http://timestamp.digicert.com/</TimeStampServer>
- </PropertyGroup>
- <PropertyGroup>
- <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <IntDir>$(Platform)\$(ConfigurationName)\</IntDir>
- <TimeStampServer>http://timestamp.digicert.com/</TimeStampServer>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <IntDir>$(Platform)\$(ConfigurationName)\</IntDir>
- <TimeStampServer>http://timestamp.digicert.com/</TimeStampServer>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <IntDir>$(Platform)\$(ConfigurationName)\</IntDir>
- <TimeStampServer>http://timestamp.digicert.com/</TimeStampServer>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <IntDir>$(Platform)\$(ConfigurationName)\</IntDir>
- <TimeStampServer>http://timestamp.digicert.com/</TimeStampServer>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <IntDir>$(Platform)\$(ConfigurationName)\</IntDir>
- <TimeStampServer>http://timestamp.digicert.com/</TimeStampServer>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <TimeStampServer>
- </TimeStampServer>
- <DiagnosticMode>true</DiagnosticMode>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <TimeStampServer>
- </TimeStampServer>
- <DiagnosticMode>true</DiagnosticMode>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <TimeStampServer>
- </TimeStampServer>
- <DiagnosticMode>true</DiagnosticMode>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <TimeStampServer>
- </TimeStampServer>
- <DiagnosticMode>true</DiagnosticMode>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <TimeStampServer>
- </TimeStampServer>
- <DiagnosticMode>true</DiagnosticMode>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">
- <TargetName>zttap200</TargetName>
- <OutDir>$(SolutionDir)\Build\$(Platform)\$(ConfigurationName)\</OutDir>
- <TimeStampServer>
- </TimeStampServer>
- <DiagnosticMode>true</DiagnosticMode>
- </PropertyGroup>
- <ItemDefinitionGroup>
- <ClCompile>
- <WppEnabled>false</WppEnabled>
- <WppScanConfigurationData Condition="'%(ClCompile. ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
- <WppKernelMode>true</WppKernelMode>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</TreatWarningAsError>
- <DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">None</DebugInformationFormat>
- <DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">None</DebugInformationFormat>
- <DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">None</DebugInformationFormat>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</TreatWarningAsError>
- <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">Level2</WarningLevel>
- <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</TreatWarningAsError>
- <DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">None</DebugInformationFormat>
- <DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">None</DebugInformationFormat>
- <DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">None</DebugInformationFormat>
- </ClCompile>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">C:\WinDDK\7600.16385.1\lib\wnet\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\i386\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">C:\WinDDK\7600.16385.1\lib\wnet\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\i386\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">C:\WinDDK\7600.16385.1\lib\wnet\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\i386\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">C:\WinDDK\7600.16385.1\lib\wnet\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\i386\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">C:\WinDDK\7600.16385.1\lib\wnet\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\i386\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">C:\WinDDK\7600.16385.1\lib\wnet\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\i386\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">C:\WinDDK\7600.16385.1\lib\wnet\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\amd64\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">C:\WinDDK\7600.16385.1\lib\wnet\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\amd64\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">C:\WinDDK\7600.16385.1\lib\wnet\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\amd64\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">C:\WinDDK\7600.16385.1\lib\wnet\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\amd64\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">C:\WinDDK\7600.16385.1\lib\wnet\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\amd64\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <Link>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">C:\WinDDK\7600.16385.1\lib\wnet\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\wnet\amd64\ntstrsafe.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <DriverSign>
- <FileDigestAlgorithm Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">SHA1</FileDigestAlgorithm>
- <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">/t "http://timestamp.digicert.com/" /d "ZeroTier One Virtual Network Port" /sha1 5809bb3255b4f32dd93619c1cf26a7df6c282a89</AdditionalOptions>
- </DriverSign>
- <DriverSign>
- <FileDigestAlgorithm Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">SHA1</FileDigestAlgorithm>
- <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">/t "http://timestamp.digicert.com/" /d "ZeroTier One Virtual Network Port" /sha1 5809bb3255b4f32dd93619c1cf26a7df6c282a89</AdditionalOptions>
- </DriverSign>
- <DriverSign>
- <FileDigestAlgorithm Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">SHA1</FileDigestAlgorithm>
- <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">/t "http://timestamp.digicert.com/" /d "ZeroTier One Virtual Network Port" /sha1 5809bb3255b4f32dd93619c1cf26a7df6c282a89</AdditionalOptions>
- </DriverSign>
- <DriverSign>
- <FileDigestAlgorithm Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">SHA1</FileDigestAlgorithm>
- <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">/t "http://timestamp.digicert.com/" /d "ZeroTier One Virtual Network Port" /sha1 5809bb3255b4f32dd93619c1cf26a7df6c282a89</AdditionalOptions>
- </DriverSign>
- <DriverSign>
- <FileDigestAlgorithm Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">SHA1</FileDigestAlgorithm>
- <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">/t "http://timestamp.digicert.com/" /d "ZeroTier One Virtual Network Port" /sha1 5809bb3255b4f32dd93619c1cf26a7df6c282a89</AdditionalOptions>
- </DriverSign>
- <DriverSign>
- <FileDigestAlgorithm Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">SHA1</FileDigestAlgorithm>
- <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">/t "http://timestamp.digicert.com/" /d "ZeroTier One Virtual Network Port" /sha1 5809bb3255b4f32dd93619c1cf26a7df6c282a89</AdditionalOptions>
- </DriverSign>
- </ItemDefinitionGroup>
- <ItemGroup>
- <Inf Include="zttap200.inf" />
- </ItemGroup>
- <ItemGroup>
- <FilesToPackage Include="$(TargetPath)" />
- <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
- </ItemGroup>
- <ItemGroup>
- <ClCompile Include="error.c">
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">true</ExcludedFromBuild>
- </ClCompile>
- <ClCompile Include="instance.c">
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">true</ExcludedFromBuild>
- </ClCompile>
- <ClCompile Include="macinfo.c">
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">true</ExcludedFromBuild>
- </ClCompile>
- <ClCompile Include="mem.c">
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">true</ExcludedFromBuild>
- </ClCompile>
- <ClCompile Include="tapdrvr.c" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="config.h" />
- <ClInclude Include="constants.h" />
- <ClInclude Include="endian.h" />
- <ClInclude Include="error.h" />
- <ClInclude Include="lock.h" />
- <ClInclude Include="macinfo.h" />
- <ClInclude Include="proto.h" />
- <ClInclude Include="prototypes.h" />
- <ClInclude Include="tap-windows.h" />
- <ClInclude Include="types.h" />
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- </ImportGroup>
-</Project> \ No newline at end of file
diff --git a/windows/TapDriver/TapDriver.vcxproj.filters b/windows/TapDriver/TapDriver.vcxproj.filters
deleted file mode 100644
index 570ea727..00000000
--- a/windows/TapDriver/TapDriver.vcxproj.filters
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup>
- <Filter Include="Source Files">
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
- <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
- </Filter>
- <Filter Include="Header Files">
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
- <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
- </Filter>
- <Filter Include="Resource Files">
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
- </Filter>
- <Filter Include="Driver Files">
- <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
- <Extensions>inf;inv;inx;mof;mc;</Extensions>
- </Filter>
- </ItemGroup>
- <ItemGroup>
- <ClCompile Include="error.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="instance.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="macinfo.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="mem.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="tapdrvr.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="constants.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="endian.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="error.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="lock.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="macinfo.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="proto.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="prototypes.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="tap-windows.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="types.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="config.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- </ItemGroup>
- <ItemGroup>
- <Inf Include="zttap200.inf">
- <Filter>Driver Files</Filter>
- </Inf>
- </ItemGroup>
-</Project> \ No newline at end of file
diff --git a/windows/TapDriver/config.h b/windows/TapDriver/config.h
deleted file mode 100644
index 28bd73f6..00000000
--- a/windows/TapDriver/config.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#define PRODUCT_NAME "ZeroTier One Virtual Network Port"
-#define PRODUCT_VERSION "2.0.0"
-#define PRODUCT_VERSION_RESOURCE 2,0,0,1
-#define PRODUCT_TAP_WIN_COMPONENT_ID "zttap200"
-#define PRODUCT_TAP_WIN_MAJOR 2
-#define PRODUCT_TAP_WIN_MINOR 0
-#define PRODUCT_TAP_WIN_PROVIDER "ZeroTier Networks"
-#define PRODUCT_TAP_WIN_DEVICE_DESCRIPTION PRODUCT_NAME
-#define PRODUCT_TAP_WIN_RELDATE "01/22/2014"
-
-#define TAP_DRIVER_MAJOR_VERSION PRODUCT_TAP_WIN_MAJOR
-#define TAP_DRIVER_MINOR_VERSION PRODUCT_TAP_WIN_MINOR
diff --git a/windows/TapDriver/constants.h b/windows/TapDriver/constants.h
deleted file mode 100644
index 78174d25..00000000
--- a/windows/TapDriver/constants.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-//====================================================================
-// Product and Version public settings
-//====================================================================
-
-#define PRODUCT_STRING PRODUCT_TAP_DEVICE_DESCRIPTION
-
-#define TAP_NDIS_MAJOR_VERSION 5
-#define TAP_NDIS_MINOR_VERSION 0
-
-//===========================================================
-// Driver constants
-//===========================================================
-
-#define ETHERNET_HEADER_SIZE (sizeof (ETH_HEADER))
-#define ETHERNET_MTU 2800 // ZeroTier One MTU
-#define ETHERNET_PACKET_SIZE (ETHERNET_MTU + ETHERNET_HEADER_SIZE)
-#define DEFAULT_PACKET_LOOKAHEAD (ETHERNET_PACKET_SIZE)
-
-#define NIC_MAX_MCAST_LIST 128 // Max length of multicast address list
-
-#define MINIMUM_MTU 576 // USE TCP Minimum MTU
-#define MAXIMUM_MTU 65536 // IP maximum MTU
-
-#define PACKET_QUEUE_SIZE 64 // tap -> userspace queue size
-#define IRP_QUEUE_SIZE 16 // max number of simultaneous i/o operations from userspace
-
-#define TAP_LITTLE_ENDIAN // affects ntohs, htonl, etc. functions
diff --git a/windows/TapDriver/endian.h b/windows/TapDriver/endian.h
deleted file mode 100644
index 0f7025d5..00000000
--- a/windows/TapDriver/endian.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef TAP_LITTLE_ENDIAN
-#define ntohs(x) RtlUshortByteSwap(x)
-#define htons(x) RtlUshortByteSwap(x)
-#define ntohl(x) RtlUlongByteSwap(x)
-#define htonl(x) RtlUlongByteSwap(x)
-#else
-#define ntohs(x) ((USHORT)(x))
-#define htons(x) ((USHORT)(x))
-#define ntohl(x) ((ULONG)(x))
-#define htonl(x) ((ULONG)(x))
-#endif
diff --git a/windows/TapDriver/error.c b/windows/TapDriver/error.c
deleted file mode 100644
index 81ef50d1..00000000
--- a/windows/TapDriver/error.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
-* TAP-Windows -- A kernel driver to provide virtual tap
-* device functionality on Windows.
-*
-* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
-*
-* This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
-* and is released under the GPL version 2 (see below).
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 2
-* as published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program (see the file COPYING included with this
-* distribution); if not, write to the Free Software Foundation, Inc.,
-* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-//-----------------
-// DEBUGGING OUTPUT
-//-----------------
-
-const char *g_LastErrorFilename;
-int g_LastErrorLineNumber;
-
-#if DBG
-
-DebugOutput g_Debug;
-
-BOOLEAN
- NewlineExists (const char *str, int len)
-{
- while (len-- > 0)
- {
- const char c = *str++;
- if (c == '\n')
- return TRUE;
- else if (c == '\0')
- break;
- }
- return FALSE;
-}
-
-VOID
- MyDebugInit (unsigned int bufsiz)
-{
- NdisZeroMemory (&g_Debug, sizeof (g_Debug));
- g_Debug.text = (char *) MemAlloc (bufsiz, FALSE);
- if (g_Debug.text)
- g_Debug.capacity = bufsiz;
-}
-
-VOID
- MyDebugFree ()
-{
- if (g_Debug.text)
- MemFree (g_Debug.text, g_Debug.capacity);
- NdisZeroMemory (&g_Debug, sizeof (g_Debug));
-}
-
-VOID
- MyDebugPrint (const unsigned char* format, ...)
-{
- if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT)
- {
- BOOLEAN owned;
- ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned);
- if (owned)
- {
- const int remaining = (int)g_Debug.capacity - (int)g_Debug.out;
-
- if (remaining > 0)
- {
- va_list args;
- NTSTATUS status;
- char *end;
-
-#ifdef DBG_PRINT
- va_start (args, format);
- vDbgPrintEx (DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, format, args);
- va_end (args);
-#endif
- va_start (args, format);
- status = RtlStringCchVPrintfExA (g_Debug.text + g_Debug.out,
- remaining,
- &end,
- NULL,
- STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS,
- format,
- args);
- va_end (args);
- va_start (args, format);
- vDbgPrintEx(DPFLTR_IHVDRIVER_ID , 1, format, args);
- va_end (args);
- if (status == STATUS_SUCCESS)
- g_Debug.out = (unsigned int) (end - g_Debug.text);
- else
- g_Debug.error = TRUE;
- }
- else
- g_Debug.error = TRUE;
-
- RELEASE_MUTEX (&g_Debug.lock);
- }
- else
- g_Debug.error = TRUE;
- }
-}
-
-BOOLEAN
- GetDebugLine (char *buf, const int len)
-{
- static const char *truncated = "[OUTPUT TRUNCATED]\n";
- BOOLEAN ret = FALSE;
-
- NdisZeroMemory (buf, len);
-
- if (g_Debug.text && g_Debug.capacity > 0)
- {
- BOOLEAN owned;
- ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned);
- if (owned)
- {
- int i = 0;
-
- if (g_Debug.error || NewlineExists (g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in))
- {
- while (i < (len - 1) && g_Debug.in < g_Debug.out)
- {
- const char c = g_Debug.text[g_Debug.in++];
- if (c == '\n')
- break;
- buf[i++] = c;
- }
- if (i < len)
- buf[i] = '\0';
- }
-
- if (!i)
- {
- if (g_Debug.in == g_Debug.out)
- {
- g_Debug.in = g_Debug.out = 0;
- if (g_Debug.error)
- {
- const unsigned int tlen = strlen (truncated);
- if (tlen < g_Debug.capacity)
- {
- NdisMoveMemory (g_Debug.text, truncated, tlen+1);
- g_Debug.out = tlen;
- }
- g_Debug.error = FALSE;
- }
- }
- }
- else
- ret = TRUE;
-
- RELEASE_MUTEX (&g_Debug.lock);
- }
- }
- return ret;
-}
-
-VOID
- MyAssert (const unsigned char *file, int line)
-{
- DEBUGP (("MYASSERT failed %s/%d\n", file, line));
- KeBugCheckEx (0x0F00BABA,
- (ULONG_PTR) line,
- (ULONG_PTR) 0,
- (ULONG_PTR) 0,
- (ULONG_PTR) 0);
-}
-
-VOID
- PrMac (const MACADDR mac)
-{
- DEBUGP (("%x:%x:%x:%x:%x:%x",
- mac[0], mac[1], mac[2],
- mac[3], mac[4], mac[5]));
-}
-
-VOID
- PrIP (IPADDR ip_addr)
-{
- const unsigned char *ip = (const unsigned char *) &ip_addr;
-
- DEBUGP (("%d.%d.%d.%d",
- ip[0], ip[1], ip[2], ip[3]));
-}
-
-const char *
- PrIPProto (int proto)
-{
- switch (proto)
- {
- case IPPROTO_UDP:
- return "UDP";
- case IPPROTO_TCP:
- return "TCP";
- case IPPROTO_ICMP:
- return "ICMP";
- case IPPROTO_IGMP:
- return "IGMP";
- default:
- return "???";
- }
-}
-
-VOID
- DumpARP (const char *prefix, const ARP_PACKET *arp)
-{
- DEBUGP (("%s ARP src=", prefix));
- PrMac (arp->m_MAC_Source);
- DEBUGP ((" dest="));
- PrMac (arp->m_MAC_Destination);
- DEBUGP ((" OP=0x%04x",
- (int)ntohs(arp->m_ARP_Operation)));
- DEBUGP ((" M=0x%04x(%d)",
- (int)ntohs(arp->m_MAC_AddressType),
- (int)arp->m_MAC_AddressSize));
- DEBUGP ((" P=0x%04x(%d)",
- (int)ntohs(arp->m_PROTO_AddressType),
- (int)arp->m_PROTO_AddressSize));
-
- DEBUGP ((" MacSrc="));
- PrMac (arp->m_ARP_MAC_Source);
- DEBUGP ((" MacDest="));
- PrMac (arp->m_ARP_MAC_Destination);
-
- DEBUGP ((" IPSrc="));
- PrIP (arp->m_ARP_IP_Source);
- DEBUGP ((" IPDest="));
- PrIP (arp->m_ARP_IP_Destination);
-
- DEBUGP (("\n"));
-}
-
-struct ethpayload {
- ETH_HEADER eth;
- UCHAR payload[DEFAULT_PACKET_LOOKAHEAD];
-};
-
-VOID
- DumpPacket2 (const char *prefix,
- const ETH_HEADER *eth,
- const unsigned char *data,
- unsigned int len)
-{
- struct ethpayload *ep = (struct ethpayload *) MemAlloc (sizeof (struct ethpayload), TRUE);
- if (ep)
- {
- if (len > DEFAULT_PACKET_LOOKAHEAD)
- len = DEFAULT_PACKET_LOOKAHEAD;
- ep->eth = *eth;
- NdisMoveMemory (ep->payload, data, len);
- DumpPacket (prefix, (unsigned char *) ep, sizeof (ETH_HEADER) + len);
- MemFree (ep, sizeof (struct ethpayload));
- }
-}
-
-VOID
- DumpPacket (const char *prefix,
- const unsigned char *data,
- unsigned int len)
-{
- const ETH_HEADER *eth = (const ETH_HEADER *) data;
- const IPHDR *ip = (const IPHDR *) (data + sizeof (ETH_HEADER));
-
- if (len < sizeof (ETH_HEADER))
- {
- DEBUGP (("%s TRUNCATED PACKET LEN=%d\n", prefix, len));
- return;
- }
-
- // ARP Packet?
- if (len >= sizeof (ARP_PACKET) && eth->proto == htons (ETH_P_ARP))
- {
- DumpARP (prefix, (const ARP_PACKET *) data);
- return;
- }
-
- // IPv4 packet?
- if (len >= (sizeof (IPHDR) + sizeof (ETH_HEADER))
- && eth->proto == htons (ETH_P_IP)
- && IPH_GET_VER (ip->version_len) == 4)
- {
- const int hlen = IPH_GET_LEN (ip->version_len);
- const int blen = len - sizeof (ETH_HEADER);
- BOOLEAN did = FALSE;
-
- DEBUGP (("%s IPv4 %s[%d]", prefix, PrIPProto (ip->protocol), len));
-
- if (!(ntohs (ip->tot_len) == blen && hlen <= blen))
- {
- DEBUGP ((" XXX"));
- return;
- }
-
- // TCP packet?
- if (ip->protocol == IPPROTO_TCP
- && blen - hlen >= (sizeof (TCPHDR)))
- {
- const TCPHDR *tcp = (TCPHDR *) (data + sizeof (ETH_HEADER) + hlen);
- DEBUGP ((" "));
- PrIP (ip->saddr);
- DEBUGP ((":%d", ntohs (tcp->source)));
- DEBUGP ((" -> "));
- PrIP (ip->daddr);
- DEBUGP ((":%d", ntohs (tcp->dest)));
- did = TRUE;
- }
-
- // UDP packet?
- else if ((ntohs (ip->frag_off) & IP_OFFMASK) == 0
- && ip->protocol == IPPROTO_UDP
- && blen - hlen >= (sizeof (UDPHDR)))
- {
- const UDPHDR *udp = (UDPHDR *) (data + sizeof (ETH_HEADER) + hlen);
-
-#if 0
- // DHCP packet?
- if ((udp->dest == htons (BOOTPC_PORT) || udp->dest == htons (BOOTPS_PORT))
- && blen - hlen >= (sizeof (UDPHDR) + sizeof (DHCP)))
- {
- const DHCP *dhcp = (DHCP *) (data
- + hlen
- + sizeof (ETH_HEADER)
- + sizeof (UDPHDR));
-
- int optlen = len
- - sizeof (ETH_HEADER)
- - hlen
- - sizeof (UDPHDR)
- - sizeof (DHCP);
-
- if (optlen < 0)
- optlen = 0;
-
- DumpDHCP (eth, ip, udp, dhcp, optlen);
- did = TRUE;
- }
-#endif
-
- if (!did)
- {
- DEBUGP ((" "));
- PrIP (ip->saddr);
- DEBUGP ((":%d", ntohs (udp->source)));
- DEBUGP ((" -> "));
- PrIP (ip->daddr);
- DEBUGP ((":%d", ntohs (udp->dest)));
- did = TRUE;
- }
- }
-
- if (!did)
- {
- DEBUGP ((" ipproto=%d ", ip->protocol));
- PrIP (ip->saddr);
- DEBUGP ((" -> "));
- PrIP (ip->daddr);
- }
-
- DEBUGP (("\n"));
- return;
- }
-
- {
- DEBUGP (("%s ??? src=", prefix));
- PrMac (eth->src);
- DEBUGP ((" dest="));
- PrMac (eth->dest);
- DEBUGP ((" proto=0x%04x len=%d\n",
- (int) ntohs(eth->proto),
- len));
- }
-}
-
-#endif
diff --git a/windows/TapDriver/error.h b/windows/TapDriver/error.h
deleted file mode 100644
index 47f436c5..00000000
--- a/windows/TapDriver/error.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-//-----------------
-// DEBUGGING OUTPUT
-//-----------------
-
-#define NOTE_ERROR() \
-{ \
- g_LastErrorFilename = __FILE__; \
- g_LastErrorLineNumber = __LINE__; \
-}
-
-#if DBG
-
-typedef struct {
- unsigned int in;
- unsigned int out;
- unsigned int capacity;
- char *text;
- BOOLEAN error;
- MUTEX lock;
-} DebugOutput;
-
-VOID MyDebugPrint (const unsigned char* format, ...);
-
-VOID MyAssert (const unsigned char *file, int line);
-
-VOID DumpPacket (const char *prefix,
- const unsigned char *data,
- unsigned int len);
-
-VOID DumpPacket2 (const char *prefix,
- const ETH_HEADER *eth,
- const unsigned char *data,
- unsigned int len);
-
-#define CAN_WE_PRINT (DEBUGP_AT_DISPATCH || KeGetCurrentIrql () < DISPATCH_LEVEL)
-
-#if ALSO_DBGPRINT
-#define DEBUGP(fmt) { MyDebugPrint fmt; if (CAN_WE_PRINT) DbgPrint fmt; }
-#else
-#define DEBUGP(fmt) { MyDebugPrint fmt; }
-#endif
-
-#define MYASSERT(exp) \
-{ \
- if (!(exp)) \
- { \
- MyAssert(__FILE__, __LINE__); \
- } \
-}
-
-#define DUMP_PACKET(prefix, data, len) \
- DumpPacket (prefix, data, len)
-
-#define DUMP_PACKET2(prefix, eth, data, len) \
- DumpPacket2 (prefix, eth, data, len)
-
-#else
-
-#define DEBUGP(fmt)
-#define MYASSERT(exp)
-#define DUMP_PACKET(prefix, data, len)
-#define DUMP_PACKET2(prefix, eth, data, len)
-
-#endif
diff --git a/windows/TapDriver/instance.c b/windows/TapDriver/instance.c
deleted file mode 100644
index 3e1034b3..00000000
--- a/windows/TapDriver/instance.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
-* TAP-Windows -- A kernel driver to provide virtual tap
-* device functionality on Windows.
-*
-* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
-*
-* This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
-* and is released under the GPL version 2 (see below).
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 2
-* as published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program (see the file COPYING included with this
-* distribution); if not, write to the Free Software Foundation, Inc.,
-* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#define INSTANCE_KEY(a) ((PVOID)((a)->m_Extension.m_TapDevice))
-
-#define N_INSTANCE_BUCKETS 256
-
-typedef struct _INSTANCE {
- struct _INSTANCE *next;
- TapAdapterPointer m_Adapter;
-} INSTANCE;
-
-typedef struct {
- INSTANCE *list;
- MUTEX lock;
-} INSTANCE_BUCKET;
-
-typedef struct {
- INSTANCE_BUCKET buckets[N_INSTANCE_BUCKETS];
-} INSTANCE_HASH;
-
-INSTANCE_HASH *g_InstanceHash = NULL;
-
-// must return a hash >= 0 and < N_INSTANCE_BUCKETS
-int
- InstanceHashValue (PVOID addr)
-{
- UCHAR *p = (UCHAR *) &addr;
-
- if (sizeof (addr) == 4)
- return p[0] ^ p[1] ^ p[2] ^ p[3];
- else if (sizeof (addr) == 8)
- return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4] ^ p[5] ^ p[6] ^ p[7];
- else
- {
- MYASSERT (0);
- }
-}
-
-BOOLEAN
- InitInstanceList (VOID)
-{
- MYASSERT (g_InstanceHash == NULL);
- g_InstanceHash = MemAlloc (sizeof (INSTANCE_HASH), TRUE);
- if (g_InstanceHash)
- {
- int i;
- for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
- INIT_MUTEX (&g_InstanceHash->buckets[i].lock);
- return TRUE;
- }
- else
- return FALSE;
-}
-
-int
- NInstances (VOID)
-{
- int i, n = 0;
-
- if (g_InstanceHash)
- {
- for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
- {
- BOOLEAN got_lock;
- INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i];
- ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
-
- if (got_lock)
- {
- INSTANCE *current;
- for (current = ib->list; current != NULL; current = current->next)
- ++n;
- RELEASE_MUTEX (&ib->lock);
- }
- else
- return -1;
- }
- }
-
- return n;
-}
-
-int
- InstanceMaxBucketSize (VOID)
-{
- int i, n = 0;
-
- if (g_InstanceHash)
- {
- for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
- {
- BOOLEAN got_lock;
- int bucket_size = 0;
- INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i];
- ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
-
- if (got_lock)
- {
- INSTANCE *current;
- for (current = ib->list; current != NULL; current = current->next)
- ++bucket_size;
- if (bucket_size > n)
- n = bucket_size;
- RELEASE_MUTEX (&ib->lock);
- }
- else
- return -1;
- }
- }
-
- return n;
-}
-
-VOID
- FreeInstanceList (VOID)
-{
- if (g_InstanceHash)
- {
- MYASSERT (NInstances() == 0);
- MemFree (g_InstanceHash, sizeof (INSTANCE_HASH));
- g_InstanceHash = NULL;
- }
-}
-
-BOOLEAN
- AddAdapterToInstanceList (TapAdapterPointer p_Adapter)
-{
- BOOLEAN got_lock;
- BOOLEAN ret = FALSE;
- const int hash = InstanceHashValue(INSTANCE_KEY(p_Adapter));
- INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[hash];
-
- DEBUGP (("[TAP] AddAdapterToInstanceList hash=%d\n", hash));
-
- ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
-
- if (got_lock)
- {
- INSTANCE *i = MemAlloc (sizeof (INSTANCE), FALSE);
- if (i)
- {
- MYASSERT (p_Adapter);
- i->m_Adapter = p_Adapter;
- i->next = ib->list;
- ib->list = i;
- ret = TRUE;
- }
- RELEASE_MUTEX (&ib->lock);
- }
-
- return ret;
-}
-
-BOOLEAN
- RemoveAdapterFromInstanceList (TapAdapterPointer p_Adapter)
-{
- BOOLEAN got_lock;
- BOOLEAN ret = FALSE;
- INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue(INSTANCE_KEY(p_Adapter))];
-
- ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
-
- if (got_lock)
- {
- INSTANCE *current, *prev=NULL;
- for (current = ib->list; current != NULL; current = current->next)
- {
- if (current->m_Adapter == p_Adapter) // found match
- {
- if (prev)
- prev->next = current->next;
- else
- ib->list = current->next;
- MemFree (current->m_Adapter, sizeof (TapAdapter));
- MemFree (current, sizeof (INSTANCE));
- ret = TRUE;
- break;
- }
- prev = current;
- }
- RELEASE_MUTEX (&ib->lock);
- }
-
- return ret;
-}
-
-TapAdapterPointer
- LookupAdapterInInstanceList (PDEVICE_OBJECT p_DeviceObject)
-{
- BOOLEAN got_lock;
- TapAdapterPointer ret = NULL;
- INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue((PVOID)p_DeviceObject)];
-
- ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
-
- if (got_lock)
- {
- INSTANCE *current, *prev=NULL;
- for (current = ib->list; current != NULL; current = current->next)
- {
- if (p_DeviceObject == INSTANCE_KEY (current->m_Adapter)) // found match
- {
- // move it to head of list
- if (prev)
- {
- prev->next = current->next;
- current->next = ib->list;
- ib->list = current;
- }
- ret = ib->list->m_Adapter;
- break;
- }
- prev = current;
- }
- RELEASE_MUTEX (&ib->lock);
- }
-
- return ret;
-}
diff --git a/windows/TapDriver/lock.h b/windows/TapDriver/lock.h
deleted file mode 100644
index e2a2029e..00000000
--- a/windows/TapDriver/lock.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-typedef struct
-{
- volatile long count;
-} MUTEX;
-
-#define MUTEX_SLEEP_TIME 10000 // microseconds
-
-#define INIT_MUTEX(m) { (m)->count = 0; }
-
-#define ACQUIRE_MUTEX_BLOCKING(m) \
-{ \
- while (NdisInterlockedIncrement (&((m)->count)) != 1) \
- { \
- NdisInterlockedDecrement(&((m)->count)); \
- NdisMSleep(MUTEX_SLEEP_TIME); \
- } \
-}
-
-#define RELEASE_MUTEX(m) \
-{ \
- NdisInterlockedDecrement(&((m)->count)); \
-}
-
-#define ACQUIRE_MUTEX_NONBLOCKING(m, result) \
-{ \
- if (NdisInterlockedIncrement (&((m)->count)) != 1) \
- { \
- NdisInterlockedDecrement(&((m)->count)); \
- result = FALSE; \
- } \
- else \
- { \
- result = TRUE; \
- } \
-}
-
-#define ACQUIRE_MUTEX_ADAPTIVE(m, result) \
-{ \
- result = TRUE; \
- while (NdisInterlockedIncrement (&((m)->count)) != 1) \
- { \
- NdisInterlockedDecrement(&((m)->count)); \
- if (KeGetCurrentIrql () < DISPATCH_LEVEL) \
- NdisMSleep(MUTEX_SLEEP_TIME); \
- else \
- { \
- result = FALSE; \
- break; \
- } \
- } \
-}
diff --git a/windows/TapDriver/macinfo.c b/windows/TapDriver/macinfo.c
deleted file mode 100644
index 95f75861..00000000
--- a/windows/TapDriver/macinfo.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
-* TAP-Windows -- A kernel driver to provide virtual tap
-* device functionality on Windows.
-*
-* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
-*
-* This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
-* and is released under the GPL version 2 (see below).
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 2
-* as published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program (see the file COPYING included with this
-* distribution); if not, write to the Free Software Foundation, Inc.,
-* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "macinfo.h"
-
-int
- HexStringToDecimalInt (const int p_Character)
-{
- int l_Value = 0;
-
- if (p_Character >= 'A' && p_Character <= 'F')
- l_Value = (p_Character - 'A') + 10;
- else if (p_Character >= 'a' && p_Character <= 'f')
- l_Value = (p_Character - 'a') + 10;
- else if (p_Character >= '0' && p_Character <= '9')
- l_Value = p_Character - '0';
-
- return l_Value;
-}
-
-BOOLEAN
- ParseMAC (MACADDR dest, const char *src)
-{
- int c;
- int mac_index = 0;
- BOOLEAN high_digit = FALSE;
- int delim_action = 1;
-
- MYASSERT (src);
- MYASSERT (dest);
-
- CLEAR_MAC (dest);
-
- while (c = *src++)
- {
- if (IsMacDelimiter (c))
- {
- mac_index += delim_action;
- high_digit = FALSE;
- delim_action = 1;
- }
- else if (IsHexDigit (c))
- {
- const int digit = HexStringToDecimalInt (c);
- if (mac_index < sizeof (MACADDR))
- {
- if (!high_digit)
- {
- dest[mac_index] = (char)(digit);
- high_digit = TRUE;
- delim_action = 1;
- }
- else
- {
- dest[mac_index] = (char)(dest[mac_index] * 16 + digit);
- ++mac_index;
- high_digit = FALSE;
- delim_action = 0;
- }
- }
- else
- return FALSE;
- }
- else
- return FALSE;
- }
-
- return (mac_index + delim_action) >= sizeof (MACADDR);
-}
-
-/*
-* Generate a MAC using the GUID in the adapter name.
-*
-* The mac is constructed as 00:FF:xx:xx:xx:xx where
-* the Xs are taken from the first 32 bits of the GUID in the
-* adapter name. This is similar to the Linux 2.4 tap MAC
-* generator, except linux uses 32 random bits for the Xs.
-*
-* In general, this solution is reasonable for most
-* applications except for very large bridged TAP networks,
-* where the probability of address collisions becomes more
-* than infintesimal.
-*
-* Using the well-known "birthday paradox", on a 1000 node
-* network the probability of collision would be
-* 0.000116292153. On a 10,000 node network, the probability
-* of collision would be 0.01157288998621678766.
-*/
-
-VOID GenerateRandomMac (MACADDR mac, const unsigned char *adapter_name)
-{
- unsigned const char *cp = adapter_name;
- unsigned char c;
- unsigned int i = 2;
- unsigned int byte = 0;
- int brace = 0;
- int state = 0;
-
- CLEAR_MAC (mac);
-
- mac[0] = 0x00;
- mac[1] = 0xFF;
-
- while (c = *cp++)
- {
- if (i >= sizeof (MACADDR))
- break;
- if (c == '{')
- brace = 1;
- if (IsHexDigit (c) && brace)
- {
- const unsigned int digit = HexStringToDecimalInt (c);
- if (state)
- {
- byte <<= 4;
- byte |= digit;
- mac[i++] = (unsigned char) byte;
- state = 0;
- }
- else
- {
- byte = digit;
- state = 1;
- }
- }
- }
-}
-
-VOID GenerateRelatedMAC (MACADDR dest, const MACADDR src, const int delta)
-{
- COPY_MAC (dest, src);
- dest[2] += (UCHAR) delta;
-}
diff --git a/windows/TapDriver/macinfo.h b/windows/TapDriver/macinfo.h
deleted file mode 100644
index ba843e8c..00000000
--- a/windows/TapDriver/macinfo.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef MacInfoDefined
-#define MacInfoDefined
-
-//===================================================================================
-// Macros
-//===================================================================================
-#define IsMacDelimiter(a) (a == ':' || a == '-' || a == '.')
-#define IsHexDigit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
-
-#define COPY_MAC(dest, src) NdisMoveMemory ((dest), (src), sizeof (MACADDR))
-#define CLEAR_MAC(dest) NdisZeroMemory ((dest), sizeof (MACADDR))
-#define MAC_EQUAL(a,b) (memcmp ((a), (b), sizeof (MACADDR)) == 0)
-
-#endif
diff --git a/windows/TapDriver/mem.c b/windows/TapDriver/mem.c
deleted file mode 100644
index 2f01616e..00000000
--- a/windows/TapDriver/mem.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
-* TAP-Windows -- A kernel driver to provide virtual tap
-* device functionality on Windows.
-*
-* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
-*
-* This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
-* and is released under the GPL version 2 (see below).
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 2
-* as published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program (see the file COPYING included with this
-* distribution); if not, write to the Free Software Foundation, Inc.,
-* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-//------------------
-// Memory Management
-//------------------
-
-PVOID
- MemAlloc (ULONG p_Size, BOOLEAN zero)
-{
- PVOID l_Return = NULL;
-
- if (p_Size)
- {
- __try
- {
- if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT')
- == NDIS_STATUS_SUCCESS)
- {
- if (zero)
- NdisZeroMemory (l_Return, p_Size);
- }
- else
- l_Return = NULL;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- l_Return = NULL;
- }
- }
-
- return l_Return;
-}
-
-VOID
- MemFree (PVOID p_Addr, ULONG p_Size)
-{
- if (p_Addr && p_Size)
- {
- __try
- {
-#if DBG
- NdisZeroMemory (p_Addr, p_Size);
-#endif
- NdisFreeMemory (p_Addr, p_Size, 0);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- }
- }
-}
-
-/*
-* Circular queue management routines.
-*/
-
-#define QUEUE_BYTE_ALLOCATION(size) \
- (sizeof (Queue) + (size * sizeof (PVOID)))
-
-#define QUEUE_ADD_INDEX(var, inc) \
-{ \
- var += inc; \
- if (var >= q->capacity) \
- var -= q->capacity; \
- MYASSERT (var < q->capacity); \
-}
-
-#define QUEUE_SANITY_CHECK() \
- MYASSERT (q != NULL && q->base < q->capacity && q->size <= q->capacity)
-
-#define QueueCount(q) (q->size)
-
-#define UPDATE_MAX_SIZE() \
-{ \
- if (q->size > q->max_size) \
- q->max_size = q->size; \
-}
-
-Queue *
- QueueInit (ULONG capacity)
-{
- Queue *q;
-
- MYASSERT (capacity > 0);
- q = (Queue *) MemAlloc (QUEUE_BYTE_ALLOCATION (capacity), TRUE);
- if (!q)
- return NULL;
-
- q->base = q->size = 0;
- q->capacity = capacity;
- q->max_size = 0;
- return q;
-}
-
-VOID
- QueueFree (Queue *q)
-{
- if (q)
- {
- QUEUE_SANITY_CHECK ();
- MemFree (q, QUEUE_BYTE_ALLOCATION (q->capacity));
- }
-}
-
-PVOID
- QueuePush (Queue *q, PVOID item)
-{
- ULONG dest;
- QUEUE_SANITY_CHECK ();
- if (q->size == q->capacity)
- return NULL;
- dest = q->base;
- QUEUE_ADD_INDEX (dest, q->size);
- q->data[dest] = item;
- ++q->size;
- UPDATE_MAX_SIZE();
- return item;
-}
-
-PVOID
- QueuePop (Queue *q)
-{
- ULONG oldbase;
- QUEUE_SANITY_CHECK ();
- if (!q->size)
- return NULL;
- oldbase = q->base;
- QUEUE_ADD_INDEX (q->base, 1);
- --q->size;
- UPDATE_MAX_SIZE();
- return q->data[oldbase];
-}
-
-PVOID
- QueueExtract (Queue *q, PVOID item)
-{
- ULONG src, dest, count, n;
- QUEUE_SANITY_CHECK ();
- n = 0;
- src = dest = q->base;
- count = q->size;
- while (count--)
- {
- if (item == q->data[src])
- {
- ++n;
- --q->size;
- }
- else
- {
- q->data[dest] = q->data[src];
- QUEUE_ADD_INDEX (dest, 1);
- }
- QUEUE_ADD_INDEX (src, 1);
- }
- if (n)
- return item;
- else
- return NULL;
-}
-
-#undef QUEUE_BYTE_ALLOCATION
-#undef QUEUE_ADD_INDEX
-#undef QUEUE_SANITY_CHECK
-#undef UPDATE_MAX_SIZE
diff --git a/windows/TapDriver/proto.h b/windows/TapDriver/proto.h
deleted file mode 100644
index 06c712bc..00000000
--- a/windows/TapDriver/proto.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-* TAP-Windows -- A kernel driver to provide virtual tap
-* device functionality on Windows.
-*
-* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
-*
-* This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
-* and is released under the GPL version 2 (see below).
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 2
-* as published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program (see the file COPYING included with this
-* distribution); if not, write to the Free Software Foundation, Inc.,
-* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-//============================================================
-// MAC address, Ethernet header, and ARP
-//============================================================
-
-#pragma pack(1)
-
-typedef unsigned char MACADDR [6];
-
-//-----------------
-// Ethernet address
-//-----------------
-
-typedef struct {
- MACADDR addr;
-} ETH_ADDR;
-
-typedef struct {
- ETH_ADDR list[NIC_MAX_MCAST_LIST];
-} MC_LIST;
-
-//----------------
-// Ethernet header
-//----------------
-
-typedef struct
-{
- MACADDR dest; /* destination eth addr */
- MACADDR src; /* source ether addr */
-
-# define ETH_P_IP 0x0800 /* IPv4 protocol */
-# define ETH_P_IPV6 0x86DD /* IPv6 protocol */
-# define ETH_P_ARP 0x0806 /* ARP protocol */
- USHORT proto; /* packet type ID field */
-} ETH_HEADER, *PETH_HEADER;
-
-#pragma pack()
diff --git a/windows/TapDriver/prototypes.h b/windows/TapDriver/prototypes.h
deleted file mode 100644
index 4062fc18..00000000
--- a/windows/TapDriver/prototypes.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef TAP_PROTOTYPES_DEFINED
-#define TAP_PROTOTYPES_DEFINED
-
-NTSTATUS DriverEntry
- (
- IN PDRIVER_OBJECT p_DriverObject,
- IN PUNICODE_STRING p_RegistryPath
- );
-
-VOID TapDriverUnload
- (
- IN PDRIVER_OBJECT p_DriverObject
- );
-
-NDIS_STATUS AdapterCreate
- (
- OUT PNDIS_STATUS p_ErrorStatus,
- OUT PUINT p_MediaIndex,
- IN PNDIS_MEDIUM p_Media,
- IN UINT p_MediaCount,
- IN NDIS_HANDLE p_AdapterHandle,
- IN NDIS_HANDLE p_ConfigurationHandle
- );
-
-VOID AdapterHalt
- (
- IN NDIS_HANDLE p_AdapterContext
- );
-
-VOID AdapterFreeResources
- (
- TapAdapterPointer p_Adapter
- );
-
-NDIS_STATUS AdapterReset
- (
- OUT PBOOLEAN p_AddressingReset,
- IN NDIS_HANDLE p_AdapterContext
- );
-
-NDIS_STATUS AdapterQuery
- (
- IN NDIS_HANDLE p_AdapterContext,
- IN NDIS_OID p_OID,
- IN PVOID p_Buffer,
- IN ULONG p_BufferLength,
- OUT PULONG p_BytesWritten,
- OUT PULONG p_BytesNeeded
- );
-
-NDIS_STATUS AdapterModify
- (
- IN NDIS_HANDLE p_AdapterContext,
- IN NDIS_OID p_OID,
- IN PVOID p_Buffer,
- IN ULONG p_BufferLength,
- OUT PULONG p_BytesRead,
- OUT PULONG p_BytesNeeded
- );
-
-NDIS_STATUS AdapterTransmit
- (
- IN NDIS_HANDLE p_AdapterContext,
- IN PNDIS_PACKET p_Packet,
- IN UINT p_Flags
- );
-
-NDIS_STATUS AdapterReceive
- (
- OUT PNDIS_PACKET p_Packet,
- OUT PUINT p_Transferred,
- IN NDIS_HANDLE p_AdapterContext,
- IN NDIS_HANDLE p_ReceiveContext,
- IN UINT p_Offset,
- IN UINT p_ToTransfer
- );
-
-NTSTATUS TapDeviceHook
- (
- IN PDEVICE_OBJECT p_DeviceObject,
- IN PIRP p_IRP
- );
-
-NDIS_STATUS CreateTapDevice
- (
- TapExtensionPointer p_Extension,
- const char *p_Name
- );
-
-VOID DestroyTapDevice
- (
- TapExtensionPointer p_Extension
- );
-
-VOID TapDeviceFreeResources
- (
- TapExtensionPointer p_Extension
- );
-
-NTSTATUS CompleteIRP
- (
- IN PIRP p_IRP,
- IN TapPacketPointer p_PacketBuffer,
- IN CCHAR PriorityBoost
- );
-
-VOID CancelIRPCallback
- (
- IN PDEVICE_OBJECT p_DeviceObject,
- IN PIRP p_IRP
- );
-
-VOID CancelIRP
- (
- TapExtensionPointer p_Extension,
- IN PIRP p_IRP,
- BOOLEAN callback
- );
-
-VOID FlushQueues
- (
- TapExtensionPointer p_Extension
- );
-
-VOID SetMediaStatus
- (
- TapAdapterPointer p_Adapter,
- BOOLEAN state
- );
-
-VOID HookDispatchFunctions();
-
-struct WIN2K_NDIS_MINIPORT_BLOCK
-{
- unsigned char opaque[16];
- UNICODE_STRING MiniportName; // how mini-port refers to us
-};
-
-#endif
diff --git a/windows/TapDriver/tap-windows.h b/windows/TapDriver/tap-windows.h
deleted file mode 100644
index 3b695e5d..00000000
--- a/windows/TapDriver/tap-windows.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __TAP_WIN_H
-#define __TAP_WIN_H
-
-/*
- * =============
- * TAP IOCTLs
- * =============
- */
-
-#define TAP_WIN_CONTROL_CODE(request,method) \
- CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
-
-#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED)
-#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED)
-#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED)
-#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED)
-#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED)
-#define TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS TAP_WIN_CONTROL_CODE (11, METHOD_BUFFERED)
-
-// Must be the same as NIC_MAX_MCAST_LIST in constants.h
-#define TAP_MAX_MCAST_LIST 128
-
-// Amount of memory that must be provided to ioctl TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS
-#define TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE (TAP_MAX_MCAST_LIST * 6)
-
-/*
- * =================
- * Registry keys
- * =================
- */
-
-#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
-#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
-
-/*
- * ======================
- * Filesystem prefixes
- * ======================
- */
-
-#define USERMODEDEVICEDIR "\\\\.\\Global\\"
-#define SYSDEVICEDIR "\\Device\\"
-#define USERDEVICEDIR "\\DosDevices\\Global\\"
-#define TAP_WIN_SUFFIX ".tap"
-
-#endif
diff --git a/windows/TapDriver/tapdrvr.c b/windows/TapDriver/tapdrvr.c
deleted file mode 100644
index d638cdf6..00000000
--- a/windows/TapDriver/tapdrvr.c
+++ /dev/null
@@ -1,2183 +0,0 @@
-/*
-* TAP-Windows -- A kernel driver to provide virtual tap
-* device functionality on Windows.
-*
-* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
-*
-* This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
-* and is released under the GPL version 2 (see below).
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License version 2
-* as published by the Free Software Foundation.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program (see the file COPYING included with this
-* distribution); if not, write to the Free Software Foundation, Inc.,
-* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-//======================================================
-// This driver is designed to work on Win 2000 or higher
-// versions of Windows.
-//
-// It is SMP-safe and handles NDIS 5 power management.
-//
-// By default we operate as a "tap" virtual ethernet
-// 802.3 interface, but we can emulate a "tun"
-// interface (point-to-point IPv4) through the
-// TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT or
-// TAP_WIN_IOCTL_CONFIG_TUN ioctl.
-//======================================================
-
-#include "tap-windows.h"
-#include "config.h"
-
-#define NDIS_MINIPORT_DRIVER
-#define BINARY_COMPATIBLE 0
-#define NDIS50_MINIPORT 1
-#define NDIS_WDM 0
-#define NDIS50 1
-#define NTSTRSAFE_LIB
-
-// Debug info output
-#define ALSO_DBGPRINT 1
-#define DEBUGP_AT_DISPATCH 0
-
-#if defined(DDKVER_MAJOR) && DDKVER_MAJOR < 5600
-#include <ndis.h>
-#include <ntstrsafe.h>
-#include <ntddk.h>
-#else
-#include <ntifs.h>
-#include <ndis.h>
-#include <ntstrsafe.h>
-#endif
-
-#include "lock.h"
-#include "constants.h"
-#include "proto.h"
-#include "error.h"
-#include "endian.h"
-#include "types.h"
-#include "prototypes.h"
-
-#include "mem.c"
-#include "macinfo.c"
-#include "error.c"
-#include "instance.c"
-
-#define IS_UP(ta) \
- ((ta)->m_InterfaceIsRunning && (ta)->m_Extension.m_TapIsRunning)
-
-#define INCREMENT_STAT(s) ++(s)
-
-#define NAME_BUFFER_SIZE 80
-
-//========================================================
-// Globals
-//========================================================
-
-NDIS_HANDLE g_NdisWrapperHandle;
-
-const UINT g_SupportedOIDList[] = {
- OID_GEN_HARDWARE_STATUS,
- OID_GEN_MEDIA_SUPPORTED,
- OID_GEN_MEDIA_IN_USE,
- OID_GEN_MAXIMUM_LOOKAHEAD,
- OID_GEN_MAC_OPTIONS,
- OID_GEN_LINK_SPEED,
- OID_GEN_TRANSMIT_BLOCK_SIZE,
- OID_GEN_RECEIVE_BLOCK_SIZE,
- OID_GEN_VENDOR_DESCRIPTION,
- OID_GEN_DRIVER_VERSION,
- OID_GEN_XMIT_OK,
- OID_GEN_RCV_OK,
- OID_GEN_XMIT_ERROR,
- OID_GEN_RCV_ERROR,
- OID_802_3_PERMANENT_ADDRESS,
- OID_802_3_CURRENT_ADDRESS,
- OID_GEN_RCV_NO_BUFFER,
- OID_802_3_RCV_ERROR_ALIGNMENT,
- OID_802_3_XMIT_ONE_COLLISION,
- OID_802_3_XMIT_MORE_COLLISIONS,
- OID_802_3_MULTICAST_LIST,
- OID_802_3_MAXIMUM_LIST_SIZE,
- OID_GEN_VENDOR_ID,
- OID_GEN_CURRENT_LOOKAHEAD,
- OID_GEN_CURRENT_PACKET_FILTER,
- OID_GEN_PROTOCOL_OPTIONS,
- OID_GEN_MAXIMUM_TOTAL_SIZE,
- OID_GEN_TRANSMIT_BUFFER_SPACE,
- OID_GEN_RECEIVE_BUFFER_SPACE,
- OID_GEN_MAXIMUM_FRAME_SIZE,
- OID_GEN_VENDOR_DRIVER_VERSION,
- OID_GEN_MAXIMUM_SEND_PACKETS,
- OID_GEN_MEDIA_CONNECT_STATUS,
- OID_GEN_SUPPORTED_LIST
-};
-
-//============================================================
-// Driver Entry
-//============================================================
-#pragma NDIS_INIT_FUNCTION (DriverEntry)
-
-DRIVER_INITIALIZE DriverEntry;
-NTSTATUS
- DriverEntry (IN PDRIVER_OBJECT p_DriverObject,
- IN PUNICODE_STRING p_RegistryPath)
-{
- NDIS_STATUS l_Status = NDIS_STATUS_FAILURE;
- NDIS_MINIPORT_CHARACTERISTICS *l_Properties = NULL;
-
- //========================================================
- // Notify NDIS that a new miniport driver is initializing.
- //========================================================
-
- NdisMInitializeWrapper (&g_NdisWrapperHandle,
- p_DriverObject,
- p_RegistryPath, NULL);
-
- //======================
- // Global initialization
- //======================
-
-#if DBG
- MyDebugInit (10000); // Allocate debugging text space
-#endif
-
- if (!InitInstanceList ())
- {
- DEBUGP (("[TAP] Allocation failed for adapter instance list\n"));
- goto cleanup;
- }
-
- //=======================================
- // Set and register miniport entry points
- //=======================================
-
- l_Properties = (NDIS_MINIPORT_CHARACTERISTICS *)MemAlloc (sizeof (NDIS_MINIPORT_CHARACTERISTICS), TRUE);
-
- if (l_Properties == NULL)
- {
- DEBUGP (("[TAP] Allocation failed for miniport entry points\n"));
- goto cleanup;
- }
-
- l_Properties->MajorNdisVersion = TAP_NDIS_MAJOR_VERSION;
- l_Properties->MinorNdisVersion = TAP_NDIS_MINOR_VERSION;
- l_Properties->InitializeHandler = AdapterCreate;
- l_Properties->HaltHandler = AdapterHalt;
- l_Properties->ResetHandler = AdapterReset; /* DISPATCH_LEVEL */
- l_Properties->TransferDataHandler = AdapterReceive; /* DISPATCH_LEVEL */
- l_Properties->SendHandler = AdapterTransmit; /* DISPATCH_LEVEL */
- l_Properties->QueryInformationHandler = AdapterQuery; /* DISPATCH_LEVEL */
- l_Properties->SetInformationHandler = AdapterModify; /* DISPATCH_LEVEL */
-
- switch (l_Status =
- NdisMRegisterMiniport (g_NdisWrapperHandle, l_Properties,
- sizeof (NDIS_MINIPORT_CHARACTERISTICS)))
- {
- case NDIS_STATUS_SUCCESS:
- {
- DEBUGP (("[TAP] version [%d.%d] %s %s registered miniport successfully\n",
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION,
- __DATE__,
- __TIME__));
- DEBUGP (("Registry Path: '%.*S'\n", p_RegistryPath->Length/2, p_RegistryPath->Buffer));
- break;
- }
-
- case NDIS_STATUS_BAD_CHARACTERISTICS:
- {
- DEBUGP (("[TAP] Miniport characteristics were badly defined\n"));
- NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
- break;
- }
-
- case NDIS_STATUS_BAD_VERSION:
- {
- DEBUGP
- (("[TAP] NDIS Version is wrong for the given characteristics\n"));
- NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
- break;
- }
-
- case NDIS_STATUS_RESOURCES:
- {
- DEBUGP (("[TAP] Insufficient resources\n"));
- NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
- break;
- }
-
- default:
- case NDIS_STATUS_FAILURE:
- {
- DEBUGP (("[TAP] Unknown fatal registration error\n"));
- NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
- break;
- }
- }
-
-cleanup:
- if (l_Properties)
- MemFree (l_Properties, sizeof (NDIS_MINIPORT_CHARACTERISTICS));
-
- if (l_Status == NDIS_STATUS_SUCCESS)
- NdisMRegisterUnloadHandler (g_NdisWrapperHandle, TapDriverUnload);
- else
- TapDriverUnload (p_DriverObject);
-
- return l_Status;
-}
-
-//============================================================
-// Driver Unload
-//============================================================
-DRIVER_UNLOAD TapDriverUnload;
-VOID
- TapDriverUnload (IN PDRIVER_OBJECT p_DriverObject)
-{
- DEBUGP (("[TAP] version [%d.%d] %s %s unloaded, instances=%d, imbs=%d\n",
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION,
- __DATE__,
- __TIME__,
- NInstances(),
- InstanceMaxBucketSize()));
-
- FreeInstanceList ();
-
- //==============================
- // Free debugging text space
- //==============================
-#if DBG
- MyDebugFree ();
-#endif
-}
-
-//==========================================================
-// Adapter Initialization
-//==========================================================
-NDIS_STATUS AdapterCreate
- (OUT PNDIS_STATUS p_ErrorStatus,
- OUT PUINT p_MediaIndex,
- IN PNDIS_MEDIUM p_Media,
- IN UINT p_MediaCount,
- IN NDIS_HANDLE p_AdapterHandle,
- IN NDIS_HANDLE p_ConfigurationHandle)
-{
- TapAdapterPointer l_Adapter = NULL;
-
- NDIS_MEDIUM l_PreferredMedium = NdisMedium802_3; // Ethernet
- BOOLEAN l_MacFromRegistry = FALSE;
- UINT l_Index;
- NDIS_STATUS status;
-
- DEBUGP (("[TAP] AdapterCreate called\n"));
-
- //====================================
- // Make sure adapter type is supported
- //====================================
-
- for (l_Index = 0;
- l_Index < p_MediaCount && p_Media[l_Index] != l_PreferredMedium;
- ++l_Index);
-
- if (l_Index == p_MediaCount)
- {
- DEBUGP (("[TAP] Unsupported adapter type [wanted: %d]\n",
- l_PreferredMedium));
- return NDIS_STATUS_UNSUPPORTED_MEDIA;
- }
-
- *p_MediaIndex = l_Index;
-
- //=========================================
- // Allocate memory for TapAdapter structure
- //=========================================
-
- l_Adapter = MemAlloc (sizeof (TapAdapter), TRUE);
-
- if (l_Adapter == NULL)
- {
- DEBUGP (("[TAP] Couldn't allocate adapter memory\n"));
- return NDIS_STATUS_RESOURCES;
- }
-
- //==========================================
- // Inform the NDIS library about significant
- // features of our virtual NIC.
- //==========================================
-
- NdisMSetAttributesEx
- (p_AdapterHandle,
- (NDIS_HANDLE) l_Adapter,
- 16,
- NDIS_ATTRIBUTE_DESERIALIZE
- | NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT
- | NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT
- | NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
- NdisInterfaceInternal);
-
- //=====================================
- // Initialize simple Adapter parameters
- //=====================================
-
- l_Adapter->m_Lookahead = DEFAULT_PACKET_LOOKAHEAD;
- l_Adapter->m_Medium = l_PreferredMedium;
- l_Adapter->m_DeviceState = '?';
- l_Adapter->m_MiniportAdapterHandle = p_AdapterHandle;
-
- //==================================
- // Allocate spinlock for controlling
- // access to multicast address list.
- //==================================
- NdisAllocateSpinLock (&l_Adapter->m_MCLock);
- l_Adapter->m_MCLockAllocated = TRUE;
-
- //====================================================
- // Register a shutdown handler which will be called
- // on system restart/shutdown to halt our virtual NIC.
- //====================================================
-
- NdisMRegisterAdapterShutdownHandler (p_AdapterHandle, l_Adapter,
- AdapterHalt);
- l_Adapter->m_RegisteredAdapterShutdownHandler = TRUE;
-
- //============================================
- // Get parameters from registry which were set
- // in the adapter advanced properties dialog.
- //============================================
- {
- NDIS_STATUS status;
- NDIS_HANDLE configHandle;
- NDIS_CONFIGURATION_PARAMETER *parm;
-
- // set defaults in case our registry query fails
- l_Adapter->m_MTU = ETHERNET_MTU;
- l_Adapter->m_MediaStateAlwaysConnected = FALSE;
- l_Adapter->m_MediaState = FALSE;
-
- NdisOpenConfiguration (&status, &configHandle, p_ConfigurationHandle);
- if (status != NDIS_STATUS_SUCCESS)
- {
- DEBUGP (("[TAP] Couldn't open adapter registry\n"));
- AdapterFreeResources (l_Adapter);
- return status;
- }
-
- //====================================
- // Allocate and construct adapter name
- //====================================
- {
-
- NDIS_STRING mkey = NDIS_STRING_CONST("MiniportName");
- NDIS_STRING vkey = NDIS_STRING_CONST("NdisVersion");
- NDIS_STATUS vstatus;
- NDIS_CONFIGURATION_PARAMETER *vparm;
-
- NdisReadConfiguration (&vstatus, &vparm, configHandle, &vkey, NdisParameterInteger);
- if (vstatus == NDIS_STATUS_SUCCESS)
- DEBUGP (("[TAP] NdisReadConfiguration NdisVersion=%X\n", vparm->ParameterData.IntegerData));
-
- NdisReadConfiguration (&status, &parm, configHandle, &mkey, NdisParameterString);
- if (status == NDIS_STATUS_SUCCESS)
- {
- if (parm->ParameterType == NdisParameterString)
- {
- DEBUGP (("[TAP] NdisReadConfiguration (MiniportName=%.*S)\n",
- parm->ParameterData.StringData.Length/2,
- parm->ParameterData.StringData.Buffer));
-
- if (RtlUnicodeStringToAnsiString (
- &l_Adapter->m_NameAnsi,
- &parm->ParameterData.StringData,
- TRUE) != STATUS_SUCCESS)
- {
- DEBUGP (("[TAP] MiniportName failed\n"));
- status = NDIS_STATUS_RESOURCES;
- }
- }
- }
- else
- {
- /* "MiniportName" is available only XP and above. Not on Windows 2000. */
- if (vstatus == NDIS_STATUS_SUCCESS && vparm->ParameterData.IntegerData == 0x50000)
- {
- /* Fallback for Windows 2000 with NDIS version 5.00.00
- Don't use this on Vista, 'NDIS_MINIPORT_BLOCK' was changed! */
- if (RtlUnicodeStringToAnsiString (&l_Adapter->m_NameAnsi,
- &((struct WIN2K_NDIS_MINIPORT_BLOCK *) p_AdapterHandle)->MiniportName,
- TRUE) != STATUS_SUCCESS)
- {
- DEBUGP (("[TAP] MiniportName (W2K) failed\n"));
- status = NDIS_STATUS_RESOURCES;
- }
- else
- {
- DEBUGP (("[TAP] MiniportName (W2K) succeeded: %s\n", l_Adapter->m_NameAnsi.Buffer));
- status = NDIS_STATUS_SUCCESS;
- }
- }
- }
- }
-
- /* Can't continue without name (see macro 'NAME') */
- if (status != NDIS_STATUS_SUCCESS || !l_Adapter->m_NameAnsi.Buffer)
- {
- NdisCloseConfiguration (configHandle);
- AdapterFreeResources (l_Adapter);
- DEBUGP (("[TAP] failed to get miniport name\n"));
- return NDIS_STATUS_RESOURCES;
- }
-
- /* Read MTU setting from registry */
- {
- NDIS_STRING key = NDIS_STRING_CONST("MTU");
- NdisReadConfiguration (&status, &parm, configHandle,
- &key, NdisParameterInteger);
- if (status == NDIS_STATUS_SUCCESS)
- {
- if (parm->ParameterType == NdisParameterInteger)
- {
- int mtu = parm->ParameterData.IntegerData;
- if (mtu < MINIMUM_MTU)
- mtu = MINIMUM_MTU;
- if (mtu > MAXIMUM_MTU)
- mtu = MAXIMUM_MTU;
- l_Adapter->m_MTU = mtu;
- }
- }
- }
-
- /* Read Media Status setting from registry */
- {
- NDIS_STRING key = NDIS_STRING_CONST("MediaStatus");
- NdisReadConfiguration (&status, &parm, configHandle,
- &key, NdisParameterInteger);
- if (status == NDIS_STATUS_SUCCESS)
- {
- if (parm->ParameterType == NdisParameterInteger)
- {
- if (parm->ParameterData.IntegerData)
- {
- l_Adapter->m_MediaStateAlwaysConnected = TRUE;
- l_Adapter->m_MediaState = TRUE;
- }
- }
- }
- }
-
- /* Read optional MAC setting from registry */
- {
- NDIS_STRING key = NDIS_STRING_CONST("MAC");
- ANSI_STRING mac_string;
- NdisReadConfiguration (&status, &parm, configHandle,
- &key, NdisParameterString);
- if (status == NDIS_STATUS_SUCCESS)
- {
- if (parm->ParameterType == NdisParameterString)
- {
- if (RtlUnicodeStringToAnsiString (&mac_string, &parm->ParameterData.StringData, TRUE) == STATUS_SUCCESS)
- {
- l_MacFromRegistry = ParseMAC (l_Adapter->m_MAC, mac_string.Buffer);
- RtlFreeAnsiString (&mac_string);
- }
- }
- }
- }
-
- NdisCloseConfiguration (configHandle);
-
- DEBUGP (("[%s] MTU=%d\n", NAME (l_Adapter), l_Adapter->m_MTU));
- }
-
- //==================================
- // Store and update MAC address info
- //==================================
-
- if (!l_MacFromRegistry)
- GenerateRandomMac (l_Adapter->m_MAC, (const unsigned char *)NAME (l_Adapter));
-
- DEBUGP (("[%s] Using MAC %x:%x:%x:%x:%x:%x\n",
- NAME (l_Adapter),
- l_Adapter->m_MAC[0], l_Adapter->m_MAC[1], l_Adapter->m_MAC[2],
- l_Adapter->m_MAC[3], l_Adapter->m_MAC[4], l_Adapter->m_MAC[5]));
-
- //====================================
- // Initialize TAP device
- //====================================
- {
- NDIS_STATUS tap_status;
- tap_status = CreateTapDevice (&l_Adapter->m_Extension, NAME (l_Adapter));
- if (tap_status != NDIS_STATUS_SUCCESS)
- {
- AdapterFreeResources (l_Adapter);
- DEBUGP (("[TAP] CreateTapDevice failed\n"));
- return tap_status;
- }
- }
-
- if (!AddAdapterToInstanceList (l_Adapter))
- {
- NOTE_ERROR ();
- TapDeviceFreeResources (&l_Adapter->m_Extension);
- AdapterFreeResources (l_Adapter);
- DEBUGP (("[TAP] AddAdapterToInstanceList failed\n"));
- return NDIS_STATUS_RESOURCES;
- }
-
- l_Adapter->m_InterfaceIsRunning = TRUE;
-
- return NDIS_STATUS_SUCCESS;
-}
-
-VOID
- AdapterHalt (IN NDIS_HANDLE p_AdapterContext)
-{
- BOOLEAN status;
-
- TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
-
- NOTE_ERROR ();
-
- l_Adapter->m_InterfaceIsRunning = FALSE;
-
- DEBUGP (("[%s] is being halted\n", NAME (l_Adapter)));
-
- DestroyTapDevice (&l_Adapter->m_Extension);
-
- // Free resources
- DEBUGP (("[%s] Freeing Resources\n", NAME (l_Adapter)));
- AdapterFreeResources (l_Adapter);
-
- status = RemoveAdapterFromInstanceList (l_Adapter);
- DEBUGP (("[TAP] RemoveAdapterFromInstanceList returned %d\n", (int) status));
-
- DEBUGP (("[TAP] version [%d.%d] %s %s AdapterHalt returning\n",
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION,
- __DATE__,
- __TIME__));
-}
-
-VOID
- AdapterFreeResources (TapAdapterPointer p_Adapter)
-{
- MYASSERT (!p_Adapter->m_CalledAdapterFreeResources);
- p_Adapter->m_CalledAdapterFreeResources = TRUE;
-
- if (p_Adapter->m_NameAnsi.Buffer)
- RtlFreeAnsiString (&p_Adapter->m_NameAnsi);
-
- if (p_Adapter->m_RegisteredAdapterShutdownHandler)
- NdisMDeregisterAdapterShutdownHandler (p_Adapter->m_MiniportAdapterHandle);
-
- if (p_Adapter->m_MCLockAllocated)
- NdisFreeSpinLock (&p_Adapter->m_MCLock);
-}
-
-VOID
- DestroyTapDevice (TapExtensionPointer p_Extension)
-{
- DEBUGP (("[%s] Destroying tap device\n", p_Extension->m_TapName));
-
- //======================================
- // Let clients know we are shutting down
- //======================================
- p_Extension->m_TapIsRunning = FALSE;
- p_Extension->m_TapOpens = 0;
- p_Extension->m_Halt = TRUE;
-
- //=====================================
- // If we are concurrently executing in
- // TapDeviceHook or AdapterTransmit,
- // give those calls time to finish.
- // Note that we must be running at IRQL
- // < DISPATCH_LEVEL in order to call
- // NdisMSleep.
- //=====================================
- NdisMSleep (500000);
-
- //===========================================================
- // Exhaust IRP and packet queues. Any pending IRPs will
- // be cancelled, causing user-space to get this error
- // on overlapped reads:
- // The I/O operation has been aborted because of either a
- // thread exit or an application request. (code=995)
- // It's important that user-space close the device handle
- // when this code is returned, so that when we finally
- // do a NdisMDeregisterDevice, the device reference count
- // is 0. Otherwise the driver will not unload even if the
- // the last adapter has been halted.
- //===========================================================
- FlushQueues (p_Extension);
- NdisMSleep (500000); // give user space time to respond to IRP cancel
-
- TapDeviceFreeResources (p_Extension);
-}
-
-VOID
- TapDeviceFreeResources (TapExtensionPointer p_Extension)
-{
- MYASSERT (p_Extension);
- MYASSERT (!p_Extension->m_CalledTapDeviceFreeResources);
- p_Extension->m_CalledTapDeviceFreeResources = TRUE;
-
- if (p_Extension->m_PacketQueue)
- QueueFree (p_Extension->m_PacketQueue);
- if (p_Extension->m_IrpQueue)
- QueueFree (p_Extension->m_IrpQueue);
-
- if (p_Extension->m_CreatedUnicodeLinkName)
- RtlFreeUnicodeString (&p_Extension->m_UnicodeLinkName);
-
- //==========================================================
- // According to DDK docs, the device is not actually deleted
- // until its reference count falls to zero. That means we
- // still need to gracefully fail TapDeviceHook requests
- // after this point, otherwise ugly things would happen if
- // the device was disabled (e.g. in the network connections
- // control panel) while a userspace app still held an open
- // file handle to it.
- //==========================================================
-
- if (p_Extension->m_TapDevice)
- {
- BOOLEAN status;
- status = (NdisMDeregisterDevice (p_Extension->m_TapDeviceHandle)
- == NDIS_STATUS_SUCCESS);
- DEBUGP (("[TAP] Deregistering TAP device, status=%d\n", (int)status));
- }
-
- if (p_Extension->m_TapName)
- MemFree (p_Extension->m_TapName, NAME_BUFFER_SIZE);
-
- if (p_Extension->m_AllocatedSpinlocks)
- {
- NdisFreeSpinLock (&p_Extension->m_QueueLock);
- }
-}
-
-//========================================================================
-// Tap Device Initialization
-//========================================================================
-
-NDIS_STATUS
- CreateTapDevice (TapExtensionPointer p_Extension, const char *p_Name)
-{
-# define SIZEOF_DISPATCH (sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1))
- PDRIVER_DISPATCH *l_Dispatch = NULL;
- ANSI_STRING l_TapString, l_LinkString;
- UNICODE_STRING l_TapUnicode;
- BOOLEAN l_FreeTapUnicode = FALSE;
- NTSTATUS l_Status, l_Return = NDIS_STATUS_SUCCESS;
- const char *l_UsableName;
-
- DEBUGP (("[TAP] version [%d.%d] creating tap device: %s\n",
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION,
- p_Name));
-
- NdisZeroMemory (p_Extension, sizeof (TapExtension));
-
- INIT_MUTEX (&p_Extension->m_OpenCloseMutex);
-
- l_LinkString.Buffer = NULL;
- l_TapString.Buffer = NULL;
-
- l_TapString.MaximumLength = l_LinkString.MaximumLength = NAME_BUFFER_SIZE;
-
- //=======================================
- // Set TAP device entry points
- //=======================================
-
- if ((l_Dispatch = MemAlloc (SIZEOF_DISPATCH, TRUE)) == NULL)
- {
- DEBUGP (("[%s] couldn't alloc TAP dispatch table\n", p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
-
- l_Dispatch[IRP_MJ_DEVICE_CONTROL] = TapDeviceHook;
- l_Dispatch[IRP_MJ_READ] = TapDeviceHook;
- l_Dispatch[IRP_MJ_WRITE] = TapDeviceHook;
- l_Dispatch[IRP_MJ_CREATE] = TapDeviceHook;
- l_Dispatch[IRP_MJ_CLOSE] = TapDeviceHook;
-
- //==================================
- // Find the beginning of the GUID
- //==================================
- l_UsableName = p_Name;
- while (*l_UsableName != '{')
- {
- if (*l_UsableName == '\0')
- {
- DEBUGP (("[%s] couldn't find leading '{' in name\n", p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
- ++l_UsableName;
- }
-
- //==================================
- // Allocate pool for TAP device name
- //==================================
-
- if ((p_Extension->m_TapName = l_TapString.Buffer =
- MemAlloc (NAME_BUFFER_SIZE, TRUE)) == NULL)
- {
- DEBUGP (("[%s] couldn't alloc TAP name buffer\n", p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
-
- //================================================
- // Allocate pool for TAP symbolic link name buffer
- //================================================
-
- if ((l_LinkString.Buffer =
- (PCHAR)MemAlloc (NAME_BUFFER_SIZE, TRUE)) == NULL)
- {
- DEBUGP (("[%s] couldn't alloc TAP symbolic link name buffer\n",
- p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
-
- //=======================================================
- // Set TAP device name
- //=======================================================
-
- l_Status = RtlStringCchPrintfExA
- (l_TapString.Buffer,
- l_TapString.MaximumLength,
- NULL,
- NULL,
- STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
- "%s%s%s",
- SYSDEVICEDIR,
- l_UsableName,
- TAP_WIN_SUFFIX);
-
- if (l_Status != STATUS_SUCCESS)
- {
- DEBUGP (("[%s] couldn't format TAP device name\n",
- p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
- l_TapString.Length = (USHORT) strlen (l_TapString.Buffer);
-
- DEBUGP (("TAP DEV NAME: '%s'\n", l_TapString.Buffer));
-
- //=======================================================
- // Set TAP link name
- //=======================================================
-
- l_Status = RtlStringCchPrintfExA
- (l_LinkString.Buffer,
- l_LinkString.MaximumLength,
- NULL,
- NULL,
- STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
- "%s%s%s",
- USERDEVICEDIR,
- l_UsableName,
- TAP_WIN_SUFFIX);
-
- if (l_Status != STATUS_SUCCESS)
- {
- DEBUGP (("[%s] couldn't format TAP device symbolic link\n",
- p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
- l_LinkString.Length = (USHORT) strlen (l_LinkString.Buffer);
-
- DEBUGP (("TAP LINK NAME: '%s'\n", l_LinkString.Buffer));
-
- //==================================================
- // Convert strings to unicode
- //==================================================
- if (RtlAnsiStringToUnicodeString (&l_TapUnicode, &l_TapString, TRUE) !=
- STATUS_SUCCESS)
- {
- DEBUGP (("[%s] couldn't alloc TAP unicode name buffer\n",
- p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
- l_FreeTapUnicode = TRUE;
-
- if (RtlAnsiStringToUnicodeString
- (&p_Extension->m_UnicodeLinkName, &l_LinkString, TRUE)
- != STATUS_SUCCESS)
- {
- DEBUGP
- (("[%s] Couldn't allocate unicode string for symbolic link name\n",
- p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
- p_Extension->m_CreatedUnicodeLinkName = TRUE;
-
- //==================================================
- // Create new TAP device with symbolic
- // link and associate with adapter.
- //==================================================
-
- l_Status = NdisMRegisterDevice
- (g_NdisWrapperHandle,
- &l_TapUnicode,
- &p_Extension->m_UnicodeLinkName,
- l_Dispatch,
- &p_Extension->m_TapDevice,
- &p_Extension->m_TapDeviceHandle
- );
-
- if (l_Status != STATUS_SUCCESS)
- {
- DEBUGP (("[%s] couldn't be created\n", p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
-
- /* Set TAP device flags */
- p_Extension->m_TapDevice->Flags |= DO_DIRECT_IO;
-
- //========================================================
- // Initialize Packet and IRP queues.
- //
- // The packet queue is used to buffer data which has been
- // "transmitted" by the virtual NIC, before user space
- // has had a chance to read it.
- //
- // The IRP queue is used to buffer pending I/O requests
- // from userspace, i.e. read requests on the TAP device
- // waiting for the system to "transmit" something through
- // the virtual NIC.
- //
- // Basically, packets in the packet queue are used
- // to satisfy IRP requests in the IRP queue.
- //
- // QueueLock is used to lock the packet queue used
- // for the TAP-Windows NIC -> User Space packet flow direction.
- //
- // All accesses to packet or IRP queues should be
- // bracketed by the QueueLock spinlock,
- // in order to be SMP-safe.
- //========================================================
-
- NdisAllocateSpinLock (&p_Extension->m_QueueLock);
- p_Extension->m_AllocatedSpinlocks = TRUE;
-
- p_Extension->m_PacketQueue = QueueInit (PACKET_QUEUE_SIZE);
- p_Extension->m_IrpQueue = QueueInit (IRP_QUEUE_SIZE);
- if (!p_Extension->m_PacketQueue
- || !p_Extension->m_IrpQueue)
- {
- DEBUGP (("[%s] couldn't alloc TAP queues\n", p_Name));
- l_Return = NDIS_STATUS_RESOURCES;
- goto cleanup;
- }
-
- //========================
- // Finalize initialization
- //========================
-
- p_Extension->m_TapIsRunning = TRUE;
-
- DEBUGP (("[%s] successfully created TAP device [%s]\n", p_Name,
- p_Extension->m_TapName));
-
-cleanup:
- if (l_FreeTapUnicode)
- RtlFreeUnicodeString (&l_TapUnicode);
- if (l_LinkString.Buffer)
- MemFree (l_LinkString.Buffer, NAME_BUFFER_SIZE);
- if (l_Dispatch)
- MemFree (l_Dispatch, SIZEOF_DISPATCH);
-
- if (l_Return != NDIS_STATUS_SUCCESS)
- TapDeviceFreeResources (p_Extension);
-
- return l_Return;
-}
-#undef SIZEOF_DISPATCH
-
-//========================================================
-// Adapter Control
-//========================================================
-NDIS_STATUS
- AdapterReset (OUT PBOOLEAN p_AddressingReset, IN NDIS_HANDLE p_AdapterContext)
-{
- TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
- DEBUGP (("[%s] is resetting\n", NAME (l_Adapter)));
- return NDIS_STATUS_SUCCESS;
-}
-
-NDIS_STATUS AdapterReceive
- (OUT PNDIS_PACKET p_Packet,
- OUT PUINT p_Transferred,
- IN NDIS_HANDLE p_AdapterContext,
- IN NDIS_HANDLE p_ReceiveContext,
- IN UINT p_Offset,
- IN UINT p_ToTransfer)
-{
- return NDIS_STATUS_SUCCESS;
-}
-
-//==============================================================
-// Adapter Option Query/Modification
-//==============================================================
-NDIS_STATUS AdapterQuery
- (IN NDIS_HANDLE p_AdapterContext,
- IN NDIS_OID p_OID,
- IN PVOID p_Buffer,
- IN ULONG p_BufferLength,
- OUT PULONG p_BytesWritten, OUT PULONG p_BytesNeeded)
-{
- TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
- TapAdapterQuery l_Query, *l_QueryPtr = &l_Query;
- NDIS_STATUS l_Status = NDIS_STATUS_SUCCESS;
- UINT l_QueryLength = 4;
- BOOLEAN lock_succeeded;
-
- NdisZeroMemory (&l_Query, sizeof (l_Query));
-
- switch (p_OID)
- {
- //===================================================================
- // Vendor & Driver version Info
- //===================================================================
- case OID_GEN_VENDOR_DESCRIPTION:
- l_QueryPtr = (TapAdapterQueryPointer) PRODUCT_TAP_WIN_DEVICE_DESCRIPTION;
- l_QueryLength = strlen (PRODUCT_TAP_WIN_DEVICE_DESCRIPTION) + 1;
- break;
-
- case OID_GEN_VENDOR_ID:
- l_Query.m_Long = 0xffffff;
- break;
-
- case OID_GEN_DRIVER_VERSION:
- l_Query.m_Short =
- (((USHORT) TAP_NDIS_MAJOR_VERSION) << 8 | (USHORT)
- TAP_NDIS_MINOR_VERSION);
- l_QueryLength = sizeof (unsigned short);
- break;
-
- case OID_GEN_VENDOR_DRIVER_VERSION:
- l_Query.m_Long =
- (((USHORT) PRODUCT_TAP_WIN_MAJOR) << 8 | (USHORT)
- PRODUCT_TAP_WIN_MINOR);
- break;
-
- //=================================================================
- // Statistics
- //=================================================================
- case OID_GEN_RCV_NO_BUFFER:
- l_Query.m_Long = 0;
- break;
-
- case OID_802_3_RCV_ERROR_ALIGNMENT:
- l_Query.m_Long = 0;
- break;
-
- case OID_802_3_XMIT_ONE_COLLISION:
- l_Query.m_Long = 0;
- break;
-
- case OID_802_3_XMIT_MORE_COLLISIONS:
- l_Query.m_Long = 0;
- break;
-
- case OID_GEN_XMIT_OK:
- l_Query.m_Long = l_Adapter->m_Tx;
- break;
-
- case OID_GEN_RCV_OK:
- l_Query.m_Long = l_Adapter->m_Rx;
- break;
-
- case OID_GEN_XMIT_ERROR:
- l_Query.m_Long = l_Adapter->m_TxErr;
- break;
-
- case OID_GEN_RCV_ERROR:
- l_Query.m_Long = l_Adapter->m_RxErr;
- break;
-
- //===================================================================
- // Device & Protocol Options
- //===================================================================
- case OID_GEN_SUPPORTED_LIST:
- l_QueryPtr = (TapAdapterQueryPointer) g_SupportedOIDList;
- l_QueryLength = sizeof (g_SupportedOIDList);
- break;
-
- case OID_GEN_MAC_OPTIONS:
- // This MUST be here !!!
- l_Query.m_Long = (NDIS_MAC_OPTION_RECEIVE_SERIALIZED
- | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA
- | NDIS_MAC_OPTION_NO_LOOPBACK
- | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND);
-
- break;
-
- case OID_GEN_CURRENT_PACKET_FILTER:
- l_Query.m_Long =
- (NDIS_PACKET_TYPE_ALL_LOCAL |
- NDIS_PACKET_TYPE_BROADCAST |
- NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_FUNCTIONAL);
-
- break;
-
- case OID_GEN_PROTOCOL_OPTIONS:
- l_Query.m_Long = 0;
- break;
-
- //==================================================================
- // Device Info
- //==================================================================
- case OID_GEN_MEDIA_CONNECT_STATUS:
- l_Query.m_Long = l_Adapter->m_MediaState
- ? NdisMediaStateConnected : NdisMediaStateDisconnected;
- break;
-
- case OID_GEN_HARDWARE_STATUS:
- l_Query.m_HardwareStatus = NdisHardwareStatusReady;
- l_QueryLength = sizeof (NDIS_HARDWARE_STATUS);
- break;
-
- case OID_GEN_MEDIA_SUPPORTED:
- case OID_GEN_MEDIA_IN_USE:
- l_Query.m_Medium = l_Adapter->m_Medium;
- l_QueryLength = sizeof (NDIS_MEDIUM);
- break;
-
- case OID_GEN_PHYSICAL_MEDIUM:
- l_Query.m_PhysicalMedium = NdisPhysicalMediumUnspecified;
- l_QueryLength = sizeof (NDIS_PHYSICAL_MEDIUM);
- break;
-
- case OID_GEN_LINK_SPEED:
- l_Query.m_Long = 100000; // rate / 100 bps
- break;
-
- case OID_802_3_PERMANENT_ADDRESS:
- case OID_802_3_CURRENT_ADDRESS:
- COPY_MAC (l_Query.m_MacAddress, l_Adapter->m_MAC);
- l_QueryLength = sizeof (MACADDR);
- break;
-
- //==================================================================
- // Limits
- //==================================================================
-
- case OID_GEN_MAXIMUM_SEND_PACKETS:
- l_Query.m_Long = 1;
- break;
-
- case OID_802_3_MAXIMUM_LIST_SIZE:
- l_Query.m_Long = NIC_MAX_MCAST_LIST;
- break;
-
- case OID_GEN_CURRENT_LOOKAHEAD:
- l_Query.m_Long = l_Adapter->m_Lookahead;
- break;
-
- case OID_GEN_MAXIMUM_LOOKAHEAD:
- case OID_GEN_MAXIMUM_TOTAL_SIZE:
- case OID_GEN_RECEIVE_BUFFER_SPACE:
- case OID_GEN_RECEIVE_BLOCK_SIZE:
- l_Query.m_Long = DEFAULT_PACKET_LOOKAHEAD;
- break;
-
- case OID_GEN_MAXIMUM_FRAME_SIZE:
- case OID_GEN_TRANSMIT_BLOCK_SIZE:
- case OID_GEN_TRANSMIT_BUFFER_SPACE:
- l_Query.m_Long = l_Adapter->m_MTU;
- break;
-
- case OID_PNP_CAPABILITIES:
- do
- {
- PNDIS_PNP_CAPABILITIES pPNPCapabilities;
- PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct;
-
- if (p_BufferLength >= sizeof (NDIS_PNP_CAPABILITIES))
- {
- pPNPCapabilities = (PNDIS_PNP_CAPABILITIES) (p_Buffer);
-
- //
- // Setting up the buffer to be returned
- // to the Protocol above the Passthru miniport
- //
- pPMstruct = &pPNPCapabilities->WakeUpCapabilities;
- pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
- pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
- pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
- }
- l_QueryLength = sizeof (NDIS_PNP_CAPABILITIES);
- }
- while (FALSE);
- break;
- case OID_PNP_QUERY_POWER:
- break;
-
- // Required OIDs that we don't support
-
- case OID_GEN_SUPPORTED_GUIDS:
- case OID_GEN_MEDIA_CAPABILITIES:
- case OID_TCP_TASK_OFFLOAD:
- case OID_FFP_SUPPORT:
- l_Status = NDIS_STATUS_INVALID_OID;
- break;
-
- // Optional stats OIDs
-
- case OID_GEN_DIRECTED_BYTES_XMIT:
- case OID_GEN_DIRECTED_FRAMES_XMIT:
- case OID_GEN_MULTICAST_BYTES_XMIT:
- case OID_GEN_MULTICAST_FRAMES_XMIT:
- case OID_GEN_BROADCAST_BYTES_XMIT:
- case OID_GEN_BROADCAST_FRAMES_XMIT:
- case OID_GEN_DIRECTED_BYTES_RCV:
- case OID_GEN_DIRECTED_FRAMES_RCV:
- case OID_GEN_MULTICAST_BYTES_RCV:
- case OID_GEN_MULTICAST_FRAMES_RCV:
- case OID_GEN_BROADCAST_BYTES_RCV:
- case OID_GEN_BROADCAST_FRAMES_RCV:
- l_Status = NDIS_STATUS_INVALID_OID;
- break;
-
- //===================================================================
- // Not Handled
- //===================================================================
- default:
- DEBUGP (("[%s] Unhandled OID %lx\n", NAME (l_Adapter), p_OID));
- l_Status = NDIS_STATUS_INVALID_OID;
- break;
- }
-
- if (l_Status != NDIS_STATUS_SUCCESS)
- ;
- else if (l_QueryLength > p_BufferLength)
- {
- l_Status = NDIS_STATUS_INVALID_LENGTH;
- *p_BytesNeeded = l_QueryLength;
- }
- else
- NdisMoveMemory (p_Buffer, (PVOID) l_QueryPtr,
- (*p_BytesWritten = l_QueryLength));
-
- return l_Status;
-}
-
-NDIS_STATUS AdapterModify
- (IN NDIS_HANDLE p_AdapterContext,
- IN NDIS_OID p_OID,
- IN PVOID p_Buffer,
- IN ULONG p_BufferLength,
- OUT PULONG p_BytesRead,
- OUT PULONG p_BytesNeeded)
-{
- TapAdapterQueryPointer l_Query = (TapAdapterQueryPointer) p_Buffer;
- TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
- NDIS_STATUS l_Status = NDIS_STATUS_INVALID_OID;
- ULONG l_Long;
-
- switch (p_OID)
- {
- //==================================================================
- // Device Info
- //==================================================================
- case OID_802_3_MULTICAST_LIST:
- DEBUGP (("[%s] Setting [OID_802_3_MULTICAST_LIST]\n",
- NAME (l_Adapter)));
-
- *p_BytesNeeded = sizeof (ETH_ADDR);
- *p_BytesRead = p_BufferLength;
-
- if (p_BufferLength % sizeof (ETH_ADDR))
- l_Status = NDIS_STATUS_INVALID_LENGTH;
- else if (p_BufferLength > sizeof (MC_LIST))
- {
- l_Status = NDIS_STATUS_MULTICAST_FULL;
- *p_BytesNeeded = sizeof (MC_LIST);
- }
- else
- {
- NdisAcquireSpinLock (&l_Adapter->m_MCLock);
-
- NdisZeroMemory(&l_Adapter->m_MCList, sizeof (MC_LIST));
-
- NdisMoveMemory(&l_Adapter->m_MCList,
- p_Buffer,
- p_BufferLength);
-
- l_Adapter->m_MCListSize = p_BufferLength / sizeof (ETH_ADDR);
-
- NdisReleaseSpinLock (&l_Adapter->m_MCLock);
-
- l_Status = NDIS_STATUS_SUCCESS;
- }
- break;
-
- case OID_GEN_CURRENT_PACKET_FILTER:
- l_Status = NDIS_STATUS_INVALID_LENGTH;
- *p_BytesNeeded = 4;
-
- if (p_BufferLength >= sizeof (ULONG))
- {
- DEBUGP
- (("[%s] Setting [OID_GEN_CURRENT_PACKET_FILTER] to [0x%02lx]\n",
- NAME (l_Adapter), l_Query->m_Long));
- l_Status = NDIS_STATUS_SUCCESS;
- *p_BytesRead = sizeof (ULONG);
- }
- break;
-
- case OID_GEN_CURRENT_LOOKAHEAD:
- if (p_BufferLength < sizeof (ULONG))
- {
- l_Status = NDIS_STATUS_INVALID_LENGTH;
- *p_BytesNeeded = 4;
- }
- else if (l_Query->m_Long > DEFAULT_PACKET_LOOKAHEAD
- || l_Query->m_Long <= 0)
- {
- l_Status = NDIS_STATUS_INVALID_DATA;
- }
- else
- {
- DEBUGP (("[%s] Setting [OID_GEN_CURRENT_LOOKAHEAD] to [%d]\n",
- NAME (l_Adapter), l_Query->m_Long));
- l_Adapter->m_Lookahead = l_Query->m_Long;
- l_Status = NDIS_STATUS_SUCCESS;
- *p_BytesRead = sizeof (ULONG);
- }
- break;
-
- case OID_GEN_NETWORK_LAYER_ADDRESSES:
- l_Status = NDIS_STATUS_SUCCESS;
- *p_BytesRead = *p_BytesNeeded = 0;
- break;
-
- case OID_GEN_TRANSPORT_HEADER_OFFSET:
- l_Status = NDIS_STATUS_SUCCESS;
- *p_BytesRead = *p_BytesNeeded = 0;
- break;
-
- case OID_PNP_SET_POWER:
- do
- {
- NDIS_DEVICE_POWER_STATE NewDeviceState;
-
- NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE) p_Buffer);
-
- switch (NewDeviceState)
- {
- case NdisDeviceStateD0:
- l_Adapter->m_DeviceState = '0';
- break;
- case NdisDeviceStateD1:
- l_Adapter->m_DeviceState = '1';
- break;
- case NdisDeviceStateD2:
- l_Adapter->m_DeviceState = '2';
- break;
- case NdisDeviceStateD3:
- l_Adapter->m_DeviceState = '3';
- break;
- default:
- l_Adapter->m_DeviceState = '?';
- break;
- }
-
- l_Status = NDIS_STATUS_FAILURE;
-
- //
- // Check for invalid length
- //
- if (p_BufferLength < sizeof (NDIS_DEVICE_POWER_STATE))
- {
- l_Status = NDIS_STATUS_INVALID_LENGTH;
- break;
- }
-
- if (NewDeviceState > NdisDeviceStateD0)
- {
- l_Adapter->m_InterfaceIsRunning = FALSE;
- DEBUGP (("[%s] Power management device state OFF\n",
- NAME (l_Adapter)));
- }
- else
- {
- l_Adapter->m_InterfaceIsRunning = TRUE;
- DEBUGP (("[%s] Power management device state ON\n",
- NAME (l_Adapter)));
- }
-
- l_Status = NDIS_STATUS_SUCCESS;
- }
- while (FALSE);
-
- if (l_Status == NDIS_STATUS_SUCCESS)
- {
- *p_BytesRead = sizeof (NDIS_DEVICE_POWER_STATE);
- *p_BytesNeeded = 0;
- }
- else
- {
- *p_BytesRead = 0;
- *p_BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
- }
- break;
-
- case OID_PNP_REMOVE_WAKE_UP_PATTERN:
- case OID_PNP_ADD_WAKE_UP_PATTERN:
- l_Status = NDIS_STATUS_SUCCESS;
- *p_BytesRead = *p_BytesNeeded = 0;
- break;
-
- default:
- DEBUGP (("[%s] Can't set value for OID %lx\n", NAME (l_Adapter),
- p_OID));
- l_Status = NDIS_STATUS_INVALID_OID;
- *p_BytesRead = *p_BytesNeeded = 0;
- break;
- }
-
- return l_Status;
-}
-
-//====================================================================
-// Adapter Transmission
-//====================================================================
-NDIS_STATUS
- AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
- IN PNDIS_PACKET p_Packet,
- IN UINT p_Flags)
-{
- TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
- ULONG l_Index = 0, l_PacketLength = 0;
- UINT l_BufferLength = 0;
- PIRP l_IRP;
- TapPacketPointer l_PacketBuffer;
- PNDIS_BUFFER l_NDIS_Buffer;
- PUCHAR l_Buffer;
- PVOID result;
-
- NdisQueryPacket (p_Packet, NULL, NULL, &l_NDIS_Buffer, &l_PacketLength);
-
- //====================================================
- // Here we abandon the transmission attempt if any of
- // the parameters is wrong or memory allocation fails
- // but we do not indicate failure. The packet is
- // silently dropped.
- //====================================================
-
- if (l_PacketLength < ETHERNET_HEADER_SIZE || l_PacketLength > 65535)
- goto exit_fail;
- else if (!l_Adapter->m_Extension.m_TapOpens || !l_Adapter->m_MediaState)
- goto exit_success; // Nothing is bound to the TAP device
-
- if (NdisAllocateMemoryWithTag (&l_PacketBuffer,
- TAP_PACKET_SIZE (l_PacketLength),
- '5PAT') != NDIS_STATUS_SUCCESS)
- goto exit_no_resources;
-
- if (l_PacketBuffer == NULL)
- goto exit_no_resources;
-
- l_PacketBuffer->m_SizeFlags = (l_PacketLength & TP_SIZE_MASK);
-
- //===========================
- // Reassemble packet contents
- //===========================
-
- __try
- {
- l_Index = 0;
- while (l_NDIS_Buffer && l_Index < l_PacketLength)
- {
- ULONG newlen;
- NdisQueryBuffer (l_NDIS_Buffer, (PVOID *) & l_Buffer,
- &l_BufferLength);
- newlen = l_Index + l_BufferLength;
- if (newlen > l_PacketLength)
- {
- NOTE_ERROR ();
- goto no_queue; /* overflow */
- }
- NdisMoveMemory (l_PacketBuffer->m_Data + l_Index, l_Buffer,
- l_BufferLength);
- l_Index = newlen;
- NdisGetNextBuffer (l_NDIS_Buffer, &l_NDIS_Buffer);
- }
- if (l_Index != l_PacketLength)
- {
- NOTE_ERROR ();
- goto no_queue; /* underflow */
- }
-
- DUMP_PACKET ("AdapterTransmit", l_PacketBuffer->m_Data, l_PacketLength);
-
- //===============================================
- // Push packet onto queue to wait for read from
- // userspace.
- //===============================================
-
- NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
-
- result = NULL;
- if (IS_UP (l_Adapter))
- result = QueuePush (l_Adapter->m_Extension.m_PacketQueue, l_PacketBuffer);
-
- NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
-
- if ((TapPacketPointer) result != l_PacketBuffer)
- {
- // adapter receive overrun
- INCREMENT_STAT (l_Adapter->m_TxErr);
- goto no_queue;
- }
- else
- {
- INCREMENT_STAT (l_Adapter->m_Tx);
- }
-
- //============================================================
- // Cycle through IRPs and packets, try to satisfy each pending
- // IRP with a queued packet.
- //============================================================
- while (TRUE)
- {
- l_IRP = NULL;
- l_PacketBuffer = NULL;
-
- NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
-
- if (IS_UP (l_Adapter)
- && QueueCount (l_Adapter->m_Extension.m_PacketQueue)
- && QueueCount (l_Adapter->m_Extension.m_IrpQueue))
- {
- l_IRP = (PIRP) QueuePop (l_Adapter->m_Extension.m_IrpQueue);
- l_PacketBuffer = (TapPacketPointer)
- QueuePop (l_Adapter->m_Extension.m_PacketQueue);
- }
-
- NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
-
- MYASSERT ((l_IRP != NULL) + (l_PacketBuffer != NULL) != 1);
-
- if (l_IRP && l_PacketBuffer)
- {
- CompleteIRP (l_IRP,
- l_PacketBuffer,
- IO_NETWORK_INCREMENT);
- }
- else
- break;
- }
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- }
-
- return NDIS_STATUS_SUCCESS;
-
-no_queue:
- NdisFreeMemory (l_PacketBuffer,
- TAP_PACKET_SIZE (l_PacketLength),
- 0);
-
-exit_success:
- return NDIS_STATUS_SUCCESS;
-
-exit_fail:
- return NDIS_STATUS_FAILURE;
-
-exit_no_resources:
- return NDIS_STATUS_RESOURCES;
-}
-
-//======================================================================
-// Hooks for catching TAP device IRP's.
-//======================================================================
-
-DRIVER_DISPATCH TapDeviceHook;
-NTSTATUS
- TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
-{
- TapAdapterPointer l_Adapter = LookupAdapterInInstanceList (p_DeviceObject);
- PIO_STACK_LOCATION l_IrpSp;
- NTSTATUS l_Status = STATUS_SUCCESS;
- BOOLEAN accessible;
- ULONG i,j;
-
- l_IrpSp = IoGetCurrentIrpStackLocation (p_IRP);
-
- p_IRP->IoStatus.Status = STATUS_SUCCESS;
- p_IRP->IoStatus.Information = 0;
-
- if (!l_Adapter || l_Adapter->m_Extension.m_Halt)
- {
- DEBUGP (("TapDeviceHook called when TAP device is halted, MajorFunction=%d\n",
- (int)l_IrpSp->MajorFunction));
-
- if (l_IrpSp->MajorFunction == IRP_MJ_CLOSE)
- {
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- return STATUS_SUCCESS;
- }
- else
- {
- p_IRP->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- return STATUS_NO_SUCH_DEVICE;
- }
- }
-
- switch (l_IrpSp->MajorFunction)
- {
- //===========================================================
- // Ioctl call handlers
- //===========================================================
- case IRP_MJ_DEVICE_CONTROL:
- {
- switch (l_IrpSp->Parameters.DeviceIoControl.IoControlCode)
- {
- case TAP_WIN_IOCTL_GET_MAC:
- {
- if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
- >= sizeof (MACADDR))
- {
- COPY_MAC (p_IRP->AssociatedIrp.SystemBuffer,
- l_Adapter->m_MAC);
- p_IRP->IoStatus.Information = sizeof (MACADDR);
- }
- else
- {
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
- }
- break;
- }
- case TAP_WIN_IOCTL_GET_VERSION:
- {
- const ULONG size = sizeof (ULONG) * 3;
- if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
- >= size)
- {
- ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0]
- = TAP_DRIVER_MAJOR_VERSION;
- ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[1]
- = TAP_DRIVER_MINOR_VERSION;
- ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[2]
-#if DBG
- = 1;
-#else
- = 0;
-#endif
- p_IRP->IoStatus.Information = size;
- }
- else
- {
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
- }
-
- break;
- }
- case TAP_WIN_IOCTL_GET_MTU:
- {
- const ULONG size = sizeof (ULONG) * 1;
- if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
- >= size)
- {
- ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0]
- = l_Adapter->m_MTU;
- p_IRP->IoStatus.Information = size;
- }
- else
- {
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
- }
-
- break;
- }
-
-#if DBG
- case TAP_WIN_IOCTL_GET_LOG_LINE:
- {
- if (GetDebugLine ((LPTSTR)p_IRP->AssociatedIrp.SystemBuffer,
- l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength))
- p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
- else
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
-
- p_IRP->IoStatus.Information
- = l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
-
- break;
- }
-#endif
-
- // Allow ZeroTier One to get multicast memberships at the L2 level in a
- // protocol-neutral manner.
- case TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS:
- {
- if (&l_Adapter->m_MCLockAllocated)
- NdisAcquireSpinLock (&l_Adapter->m_MCLock);
- if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength < TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE) {
- /* output buffer too small */
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
- } else {
- char *out = (char *)p_IRP->AssociatedIrp.SystemBuffer;
- char *end = out + TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE;
- for(i=0;i<l_Adapter->m_MCListSize;++i) {
- if (i >= TAP_MAX_MCAST_LIST)
- break;
- for(j=0;j<6;++j)
- *(out++) = l_Adapter->m_MCList.list[i].addr[j];
- if (out >= end)
- break;
- }
- while (out < end)
- *(out++) = (char)0;
- p_IRP->IoStatus.Information
- = l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
- p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
- }
- if (&l_Adapter->m_MCLockAllocated)
- NdisReleaseSpinLock (&l_Adapter->m_MCLock);
-
- break;
- }
-
- case TAP_WIN_IOCTL_SET_MEDIA_STATUS:
- {
- if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
- (sizeof (ULONG) * 1))
- {
- ULONG parm = ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0];
- SetMediaStatus (l_Adapter, (BOOLEAN) parm);
- p_IRP->IoStatus.Information = 1;
- }
- else
- {
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
- }
- break;
- }
-
- default:
- {
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
- break;
- }
- }
-
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
-
- //===========================================================
- // User mode thread issued a read request on the tap device
- // If there are packets waiting to be read, then the request
- // will be satisfied here. If not, then the request will be
- // queued and satisfied by any packet that is not used to
- // satisfy requests ahead of it.
- //===========================================================
- case IRP_MJ_READ:
- {
- TapPacketPointer l_PacketBuffer;
- BOOLEAN pending = FALSE;
-
- // Save IRP-accessible copy of buffer length
- p_IRP->IoStatus.Information = l_IrpSp->Parameters.Read.Length;
-
- if (p_IRP->MdlAddress == NULL)
- {
- DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n",
- NAME (l_Adapter)));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
- p_IRP->IoStatus.Information = 0;
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
- else if ((p_IRP->AssociatedIrp.SystemBuffer =
- MmGetSystemAddressForMdlSafe
- (p_IRP->MdlAddress, NormalPagePriority)) == NULL)
- {
- DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n",
- NAME (l_Adapter)));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_INSUFFICIENT_RESOURCES;
- p_IRP->IoStatus.Information = 0;
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
- else if (!l_Adapter->m_InterfaceIsRunning)
- {
- DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n",
- NAME (l_Adapter)));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
- p_IRP->IoStatus.Information = 0;
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
-
- //==================================
- // Can we provide immediate service?
- //==================================
-
- l_PacketBuffer = NULL;
-
- NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
-
- if (IS_UP (l_Adapter)
- && QueueCount (l_Adapter->m_Extension.m_PacketQueue)
- && QueueCount (l_Adapter->m_Extension.m_IrpQueue) == 0)
- {
- l_PacketBuffer = (TapPacketPointer)
- QueuePop (l_Adapter->m_Extension.m_PacketQueue);
- }
-
- NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
-
- if (l_PacketBuffer)
- {
- l_Status = CompleteIRP (p_IRP,
- l_PacketBuffer,
- IO_NO_INCREMENT);
- break;
- }
-
- //=============================
- // Attempt to pend read request
- //=============================
-
- NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
-
- if (IS_UP (l_Adapter)
- && QueuePush (l_Adapter->m_Extension.m_IrpQueue, p_IRP) == (PIRP) p_IRP)
- {
- IoSetCancelRoutine (p_IRP, CancelIRPCallback);
- l_Status = STATUS_PENDING;
- IoMarkIrpPending (p_IRP);
- pending = TRUE;
- }
-
- NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
-
- if (pending)
- break;
-
- // Can't queue anymore IRP's
- DEBUGP (("[%s] TAP [%s] read IRP overrun\n",
- NAME (l_Adapter), l_Adapter->m_Extension.m_TapName));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
- p_IRP->IoStatus.Information = 0;
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
-
- //==============================================================
- // User mode issued a WriteFile request on the TAP file handle.
- // The request will always get satisfied here. The call may
- // fail if there are too many pending packets (queue full).
- //==============================================================
- case IRP_MJ_WRITE:
- {
- if (p_IRP->MdlAddress == NULL)
- {
- DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
- NAME (l_Adapter)));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
- p_IRP->IoStatus.Information = 0;
- }
- else if ((p_IRP->AssociatedIrp.SystemBuffer =
- MmGetSystemAddressForMdlSafe
- (p_IRP->MdlAddress, NormalPagePriority)) == NULL)
- {
- DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
- NAME (l_Adapter)));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_INSUFFICIENT_RESOURCES;
- p_IRP->IoStatus.Information = 0;
- }
- else if (!l_Adapter->m_InterfaceIsRunning)
- {
- DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
- NAME (l_Adapter)));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
- p_IRP->IoStatus.Information = 0;
- }
- else if ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE)
- {
- __try
- {
- p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length;
-
- DUMP_PACKET ("IRP_MJ_WRITE ETH",
- (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
- l_IrpSp->Parameters.Write.Length);
-
- NdisMEthIndicateReceive
- (l_Adapter->m_MiniportAdapterHandle,
- (NDIS_HANDLE) l_Adapter,
- (PCHAR)p_IRP->AssociatedIrp.SystemBuffer,
- ETHERNET_HEADER_SIZE,
- (unsigned char *)p_IRP->AssociatedIrp.SystemBuffer + ETHERNET_HEADER_SIZE,
- l_IrpSp->Parameters.Write.Length - ETHERNET_HEADER_SIZE,
- l_IrpSp->Parameters.Write.Length - ETHERNET_HEADER_SIZE);
-
- NdisMEthIndicateReceiveComplete (l_Adapter->m_MiniportAdapterHandle);
-
- p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE\n",
- NAME (l_Adapter)));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
- p_IRP->IoStatus.Information = 0;
- }
- }
- else
- {
- DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
- NAME (l_Adapter),
- l_IrpSp->Parameters.Write.Length));
- NOTE_ERROR ();
- p_IRP->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE;
- p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
- }
-
- if (l_Status == STATUS_SUCCESS)
- INCREMENT_STAT (l_Adapter->m_Rx);
- else
- INCREMENT_STAT (l_Adapter->m_RxErr);
-
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
-
- //--------------------------------------------------------------
- // User mode thread has called CreateFile() on the tap device
- //--------------------------------------------------------------
- case IRP_MJ_CREATE:
- {
- BOOLEAN succeeded = FALSE;
- BOOLEAN mutex_succeeded;
-
- DEBUGP
- (("[%s] [TAP] release [%d.%d] open request (m_TapOpens=%d)\n",
- NAME (l_Adapter), TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION, l_Adapter->m_Extension.m_TapOpens));
-
- ACQUIRE_MUTEX_ADAPTIVE (&l_Adapter->m_Extension.m_OpenCloseMutex, mutex_succeeded);
- if (mutex_succeeded)
- {
- if (l_Adapter->m_Extension.m_TapIsRunning && !l_Adapter->m_Extension.m_TapOpens)
- {
- l_Adapter->m_Extension.m_TapOpens = 1;
- succeeded = TRUE;
- }
-
- if (succeeded)
- {
- INCREMENT_STAT (l_Adapter->m_Extension.m_NumTapOpens);
- p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
- p_IRP->IoStatus.Information = 0;
- }
- else
- {
- DEBUGP (("[%s] TAP is presently unavailable (m_TapOpens=%d)\n",
- NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
- p_IRP->IoStatus.Information = 0;
- }
-
- RELEASE_MUTEX (&l_Adapter->m_Extension.m_OpenCloseMutex);
- }
- else
- {
- DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n",
- NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
- p_IRP->IoStatus.Information = 0;
- }
-
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
-
- //-----------------------------------------------------------
- // User mode thread called CloseHandle() on the tap device
- //-----------------------------------------------------------
- case IRP_MJ_CLOSE:
- {
- BOOLEAN mutex_succeeded;
-
- DEBUGP (("[%s] [TAP] release [%d.%d] close/cleanup request\n",
- NAME (l_Adapter), TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION));
-
- ACQUIRE_MUTEX_ADAPTIVE (&l_Adapter->m_Extension.m_OpenCloseMutex, mutex_succeeded);
- if (mutex_succeeded)
- {
- l_Adapter->m_Extension.m_TapOpens = 0;
- FlushQueues (&l_Adapter->m_Extension);
- SetMediaStatus (l_Adapter, FALSE);
- RELEASE_MUTEX (&l_Adapter->m_Extension.m_OpenCloseMutex);
- }
- else
- {
- DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n",
- NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
- p_IRP->IoStatus.Information = 0;
- }
-
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
-
- //------------------
- // Strange Request
- //------------------
- default:
- {
- //NOTE_ERROR ();
- p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
- break;
- }
- }
-
- return l_Status;
-}
-
-//=============================================================
-// CompleteIRP is normally called with an adapter -> userspace
-// network packet and an IRP (Pending I/O request) from userspace.
-//
-// The IRP will normally represent a queued overlapped read
-// operation from userspace that is in a wait state.
-//
-// Use the ethernet packet to satisfy the IRP.
-//=============================================================
-
-NTSTATUS
- CompleteIRP (IN PIRP p_IRP,
- IN TapPacketPointer p_PacketBuffer,
- IN CCHAR PriorityBoost)
-{
- NTSTATUS l_Status = STATUS_UNSUCCESSFUL;
-
- int offset;
- int len;
-
- MYASSERT (p_IRP);
- MYASSERT (p_PacketBuffer);
-
- IoSetCancelRoutine (p_IRP, NULL); // Disable cancel routine
-
- //-------------------------------------------
- // While p_PacketBuffer always contains a
- // full ethernet packet, including the
- // ethernet header, in point-to-point mode,
- // we only want to return the IPv4
- // component.
- //-------------------------------------------
-
- if (p_PacketBuffer->m_SizeFlags & TP_TUN)
- {
- offset = ETHERNET_HEADER_SIZE;
- len = (int) (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE;
- }
- else
- {
- offset = 0;
- len = (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK);
- }
-
- if (len < 0 || (int) p_IRP->IoStatus.Information < len)
- {
- p_IRP->IoStatus.Information = 0;
- p_IRP->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
- NOTE_ERROR ();
- }
- else
- {
- p_IRP->IoStatus.Information = len;
- p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
-
- __try
- {
- NdisMoveMemory (p_IRP->AssociatedIrp.SystemBuffer,
- p_PacketBuffer->m_Data + offset,
- len);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- NOTE_ERROR ();
- p_IRP->IoStatus.Status = STATUS_UNSUCCESSFUL;
- p_IRP->IoStatus.Information = 0;
- }
- }
-
- __try
- {
- NdisFreeMemory (p_PacketBuffer,
- TAP_PACKET_SIZE (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK),
- 0);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- }
-
- if (l_Status == STATUS_SUCCESS)
- {
- IoCompleteRequest (p_IRP, PriorityBoost);
- }
- else
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
-
- return l_Status;
-}
-
-//==============================================
-// IRPs get cancelled for a number of reasons.
-//
-// The TAP device could be closed by userspace
-// when there are still pending read operations.
-//
-// The user could disable the TAP adapter in the
-// network connections control panel, while the
-// device is still open by a process.
-//==============================================
-VOID
- CancelIRPCallback (IN PDEVICE_OBJECT p_DeviceObject,
- IN PIRP p_IRP)
-{
- TapAdapterPointer l_Adapter = LookupAdapterInInstanceList (p_DeviceObject);
- CancelIRP (l_Adapter ? &l_Adapter->m_Extension : NULL, p_IRP, TRUE);
-}
-
-VOID
- CancelIRP (TapExtensionPointer p_Extension,
- IN PIRP p_IRP,
- BOOLEAN callback)
-{
- BOOLEAN exists = FALSE;
-
- MYASSERT (p_IRP);
-
- if (p_Extension)
- {
- NdisAcquireSpinLock (&p_Extension->m_QueueLock);
- exists = (QueueExtract (p_Extension->m_IrpQueue, p_IRP) == p_IRP);
- NdisReleaseSpinLock (&p_Extension->m_QueueLock);
- }
- else
- exists = TRUE;
-
- if (exists)
- {
- IoSetCancelRoutine (p_IRP, NULL);
- p_IRP->IoStatus.Status = STATUS_CANCELLED;
- p_IRP->IoStatus.Information = 0;
- }
-
- if (callback)
- IoReleaseCancelSpinLock (p_IRP->CancelIrql);
-
- if (exists)
- IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
-}
-
-//===========================================
-// Exhaust packet, IRP, and injection queues.
-//===========================================
-VOID
- FlushQueues (TapExtensionPointer p_Extension)
-{
- PIRP l_IRP;
- TapPacketPointer l_PacketBuffer;
-
- MYASSERT (p_Extension);
- MYASSERT (p_Extension->m_TapDevice);
-
- while (TRUE)
- {
- NdisAcquireSpinLock (&p_Extension->m_QueueLock);
- l_IRP = (PIRP)QueuePop (p_Extension->m_IrpQueue);
- NdisReleaseSpinLock (&p_Extension->m_QueueLock);
- if (l_IRP)
- {
- CancelIRP (NULL, l_IRP, FALSE);
- }
- else
- break;
- }
-
- while (TRUE)
- {
- NdisAcquireSpinLock (&p_Extension->m_QueueLock);
- l_PacketBuffer = (TapPacketPointer)QueuePop (p_Extension->m_PacketQueue);
- NdisReleaseSpinLock (&p_Extension->m_QueueLock);
- if (l_PacketBuffer)
- {
- MemFree (l_PacketBuffer, TAP_PACKET_SIZE (l_PacketBuffer->m_SizeFlags & TP_SIZE_MASK));
- }
- else
- break;
- }
-}
-
-//===================================================
-// Tell Windows whether the TAP device should be
-// considered "connected" or "disconnected".
-//===================================================
-VOID
- SetMediaStatus (TapAdapterPointer p_Adapter, BOOLEAN state)
-{
- if (p_Adapter->m_MediaState != state && !p_Adapter->m_MediaStateAlwaysConnected)
- {
- if (state)
- NdisMIndicateStatus (p_Adapter->m_MiniportAdapterHandle,
- NDIS_STATUS_MEDIA_CONNECT, NULL, 0);
- else
- NdisMIndicateStatus (p_Adapter->m_MiniportAdapterHandle,
- NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0);
-
- NdisMIndicateStatusComplete (p_Adapter->m_MiniportAdapterHandle);
- p_Adapter->m_MediaState = state;
- }
-}
diff --git a/windows/TapDriver/types.h b/windows/TapDriver/types.h
deleted file mode 100644
index 94587a64..00000000
--- a/windows/TapDriver/types.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef TAP_TYPES_DEFINED
-#define TAP_TYPES_DEFINED
-
-typedef struct _Queue
-{
- ULONG base;
- ULONG size;
- ULONG capacity;
- ULONG max_size;
- PVOID data[];
-} Queue;
-
-typedef struct _TapAdapter;
-typedef struct _TapPacket;
-
-typedef union _TapAdapterQuery
-{
- NDIS_HARDWARE_STATUS m_HardwareStatus;
- NDIS_MEDIUM m_Medium;
- NDIS_PHYSICAL_MEDIUM m_PhysicalMedium;
- UCHAR m_MacAddress [6];
- UCHAR m_Buffer [256];
- ULONG m_Long;
- USHORT m_Short;
- UCHAR m_Byte;
-}
-TapAdapterQuery, *TapAdapterQueryPointer;
-
-typedef struct _TapExtension
-{
- // TAP device object and packet queues
- Queue *m_PacketQueue, *m_IrpQueue;
- PDEVICE_OBJECT m_TapDevice;
- NDIS_HANDLE m_TapDeviceHandle;
- ULONG m_TapOpens;
-
- // Used to lock packet queues
- NDIS_SPIN_LOCK m_QueueLock;
- BOOLEAN m_AllocatedSpinlocks;
-
- // Used to bracket open/close
- // state changes.
- MUTEX m_OpenCloseMutex;
-
- // True if device has been permanently halted
- BOOLEAN m_Halt;
-
- // TAP device name
- unsigned char *m_TapName;
- UNICODE_STRING m_UnicodeLinkName;
- BOOLEAN m_CreatedUnicodeLinkName;
-
- // Used for device status ioctl only
- const char *m_LastErrorFilename;
- int m_LastErrorLineNumber;
- LONG m_NumTapOpens;
-
- // Flags
- BOOLEAN m_TapIsRunning;
- BOOLEAN m_CalledTapDeviceFreeResources;
-}
-TapExtension, *TapExtensionPointer;
-
-typedef struct _TapPacket
- {
-# define TAP_PACKET_SIZE(data_size) (sizeof (TapPacket) + (data_size))
-# define TP_TUN 0x80000000
-# define TP_SIZE_MASK (~TP_TUN)
- ULONG m_SizeFlags;
- UCHAR m_Data []; // m_Data must be the last struct member
- }
-TapPacket, *TapPacketPointer;
-
-typedef struct _TapAdapter
-{
-# define NAME(a) ((a)->m_NameAnsi.Buffer)
- ANSI_STRING m_NameAnsi;
- MACADDR m_MAC;
- BOOLEAN m_InterfaceIsRunning;
- NDIS_HANDLE m_MiniportAdapterHandle;
- LONG m_Rx, m_Tx, m_RxErr, m_TxErr;
- NDIS_MEDIUM m_Medium;
- ULONG m_Lookahead;
- ULONG m_MTU;
-
- // TRUE if adapter should always be
- // "connected" even when device node
- // is not open by a userspace process.
- BOOLEAN m_MediaStateAlwaysConnected;
-
- // TRUE if device is "connected"
- BOOLEAN m_MediaState;
-
- // Adapter power state
- char m_DeviceState;
-
- // Help to tear down the adapter by keeping
- // some state information on allocated
- // resources.
- BOOLEAN m_CalledAdapterFreeResources;
- BOOLEAN m_RegisteredAdapterShutdownHandler;
-
- // Multicast list info
- NDIS_SPIN_LOCK m_MCLock;
- BOOLEAN m_MCLockAllocated;
- ULONG m_MCListSize;
- MC_LIST m_MCList;
-
- // Information on the TAP device
- TapExtension m_Extension;
-} TapAdapter, *TapAdapterPointer;
-
-#endif
diff --git a/windows/TapDriver/zttap200.inf b/windows/TapDriver/zttap200.inf
deleted file mode 100644
index fdd05f53..00000000
--- a/windows/TapDriver/zttap200.inf
+++ /dev/null
@@ -1,78 +0,0 @@
-[Version]
-Signature="$WINDOWS NT$"
-Class=Net
-ClassGuid={4d36e972-e325-11ce-bfc1-08002be10318}
-Provider=%Provider%
-CatalogFile=zttap200.cat
-
-[Strings]
-DeviceDescription = "ZeroTier One Virtual Network Port"
-Provider = "ZeroTier Networks LLC"
-
-; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
-[Manufacturer]
-%Provider%=zttap200,NTamd64
-
-[zttap200]
-%DeviceDescription%=zttap200.ndi,zttap200
-
-[ztTap200.NTamd64]
-%DeviceDescription%=zttap200.ndi,zttap200
-
-[zttap200.ndi]
-CopyFiles = zttap200.driver,zttap200.files
-AddReg = zttap200.reg
-AddReg = zttap200.params.reg
-Characteristics = 0x81
-
-[zttap200.ndi.Services]
-AddService = zttap200, 2, zttap200.service
-
-[zttap200.reg]
-HKR, Ndi, Service, 0, "zttap200"
-HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
-HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
-HKR, , Manufacturer, 0, "%Provider%"
-HKR, , ProductName, 0, "%DeviceDescription%"
-
-[zttap200.params.reg]
-HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
-HKR, Ndi\params\MTU, Type, 0, "int"
-HKR, Ndi\params\MTU, Default, 0, "2800"
-HKR, Ndi\params\MTU, Optional, 0, "0"
-HKR, Ndi\params\MTU, Min, 0, "100"
-HKR, Ndi\params\MTU, Max, 0, "2800"
-HKR, Ndi\params\MTU, Step, 0, "1"
-HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
-HKR, Ndi\params\MediaStatus, Type, 0, "enum"
-HKR, Ndi\params\MediaStatus, Default, 0, "0"
-HKR, Ndi\params\MediaStatus, Optional, 0, "0"
-HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
-HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
-HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
-HKR, Ndi\params\MAC, Type, 0, "edit"
-HKR, Ndi\params\MAC, Optional, 0, "1"
-
-[zttap200.service]
-DisplayName = %DeviceDescription%
-ServiceType = 1
-StartType = 3
-ErrorControl = 1
-LoadOrderGroup = NDIS
-ServiceBinary = %12%\zttap200.sys
-
-[SourceDisksNames]
-1 = %DeviceDescription%, zttap200.sys
-
-[SourceDisksFiles]
-zttap200.sys = 1
-
-[DestinationDirs]
-zttap200.files = 11
-zttap200.driver = 12
-
-[zttap200.files]
-;
-
-[zttap200.driver]
-zttap200.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
diff --git a/windows/WebUIWrapper/Form1.Designer.cs b/windows/WebUIWrapper/Form1.Designer.cs
deleted file mode 100644
index 81d69cd0..00000000
--- a/windows/WebUIWrapper/Form1.Designer.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-namespace WebUIWrapper
-{
- partial class Form1
- {
- /// <summary>
- /// Required designer variable.
- /// </summary>
- private System.ComponentModel.IContainer components = null;
-
- /// <summary>
- /// Clean up any resources being used.
- /// </summary>
- /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
- protected override void Dispose(bool disposing)
- {
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
- }
-
- #region Windows Form Designer generated code
-
- /// <summary>
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- /// </summary>
- private void InitializeComponent()
- {
- System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
- this.webContainer = new System.Windows.Forms.WebBrowser();
- this.SuspendLayout();
- //
- // webContainer
- //
- this.webContainer.AllowNavigation = false;
- this.webContainer.Dock = System.Windows.Forms.DockStyle.Fill;
- this.webContainer.Location = new System.Drawing.Point(0, 0);
- this.webContainer.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
- this.webContainer.MinimumSize = new System.Drawing.Size(18, 16);
- this.webContainer.Name = "webContainer";
- this.webContainer.Size = new System.Drawing.Size(900, 445);
- this.webContainer.TabIndex = 0;
- //
- // Form1
- //
- this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(900, 445);
- this.Controls.Add(this.webContainer);
- this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
- this.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
- this.Name = "Form1";
- this.Text = "ZeroTier One";
- this.Load += new System.EventHandler(this.Form1_Load);
- this.ResumeLayout(false);
-
- }
-
- #endregion
-
- private System.Windows.Forms.WebBrowser webContainer;
- }
-}
-
diff --git a/windows/WebUIWrapper/Form1.cs b/windows/WebUIWrapper/Form1.cs
deleted file mode 100644
index 40d5da9d..00000000
--- a/windows/WebUIWrapper/Form1.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-
-namespace WebUIWrapper
-{
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
-
- private void Form1_Load(object sender, EventArgs e)
- {
- String ztDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\ZeroTier\\One";
- String authToken = "";
- Int32 port = 9993;
- try
- {
- byte[] tmp = File.ReadAllBytes(ztDir + "\\authtoken.secret");
- authToken = System.Text.Encoding.ASCII.GetString(tmp).Trim();
- } catch {
- MessageBox.Show("Unable to read ZeroTier One authtoken.secret from:\r\n" + ztDir,"ZeroTier One");
- this.Close();
- }
- if ((authToken == null)||(authToken.Length <= 0))
- {
- MessageBox.Show("Unable to read ZeroTier One authtoken.secret from:\r\n" + ztDir, "ZeroTier One");
- this.Close();
- }
- try
- {
- byte[] tmp = File.ReadAllBytes(ztDir + "\\zerotier-one.port");
- port = Int32.Parse(System.Text.Encoding.ASCII.GetString(tmp).Trim());
- if ((port <= 0) || (port > 65535))
- port = 9993;
- }
- catch
- {
- }
- try
- {
- TcpClient tc = new TcpClient();
- try
- {
- tc.Connect("127.0.0.1", port);
- tc.Close();
- }
- catch
- {
- MessageBox.Show("ZeroTier One service does not appear to be running at local port " + port.ToString(),"ZeroTier One");
- this.Close();
- return;
- }
- webContainer.Navigate("http://127.0.0.1:" + port.ToString() + "/index.html?authToken=" + authToken);
- }
- catch
- {
- MessageBox.Show("Unable to open service control panel.", "ZeroTier One");
- this.Close();
- }
- }
- }
-}
diff --git a/windows/WebUIWrapper/Form1.resx b/windows/WebUIWrapper/Form1.resx
deleted file mode 100644
index 3548e2a1..00000000
--- a/windows/WebUIWrapper/Form1.resx
+++ /dev/null
@@ -1,6293 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
- <!--
- Microsoft ResX Schema
-
- Version 2.0
-
- The primary goals of this format is to allow a simple XML format
- that is mostly human readable. The generation and parsing of the
- various data types are done through the TypeConverter classes
- associated with the data types.
-
- Example:
-
- ... ado.net/XML headers & schema ...
- <resheader name="resmimetype">text/microsoft-resx</resheader>
- <resheader name="version">2.0</resheader>
- <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
- <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
- <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
- <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
- <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
- <value>[base64 mime encoded serialized .NET Framework object]</value>
- </data>
- <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
- <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
- <comment>This is a comment</comment>
- </data>
-
- There are any number of "resheader" rows that contain simple
- name/value pairs.
-
- Each data row contains a name, and value. The row also contains a
- type or mimetype. Type corresponds to a .NET class that support
- text/value conversion through the TypeConverter architecture.
- Classes that don't support this are serialized and stored with the
- mimetype set.
-
- The mimetype is used for serialized objects, and tells the
- ResXResourceReader how to depersist the object. This is currently not
- extensible. For a given mimetype the value must be set accordingly:
-
- Note - application/x-microsoft.net.object.binary.base64 is the format
- that the ResXResourceWriter will generate, however the reader can
- read any of the formats listed below.
-
- mimetype: application/x-microsoft.net.object.binary.base64
- value : The object must be serialized with
- : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
- : and then encoded with base64 encoding.
-
- mimetype: application/x-microsoft.net.object.soap.base64
- value : The object must be serialized with
- : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
- : and then encoded with base64 encoding.
-
- mimetype: application/x-microsoft.net.object.bytearray.base64
- value : The object must be serialized into a byte array
- : using a System.ComponentModel.TypeConverter
- : and then encoded with base64 encoding.
- -->
- <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
- <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
- <xsd:element name="root" msdata:IsDataSet="true">
- <xsd:complexType>
- <xsd:choice maxOccurs="unbounded">
- <xsd:element name="metadata">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" />
- </xsd:sequence>
- <xsd:attribute name="name" use="required" type="xsd:string" />
- <xsd:attribute name="type" type="xsd:string" />
- <xsd:attribute name="mimetype" type="xsd:string" />
- <xsd:attribute ref="xml:space" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="assembly">
- <xsd:complexType>
- <xsd:attribute name="alias" type="xsd:string" />
- <xsd:attribute name="name" type="xsd:string" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="data">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
- <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
- <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
- <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
- <xsd:attribute ref="xml:space" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="resheader">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required" />
- </xsd:complexType>
- </xsd:element>
- </xsd:choice>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- <resheader name="resmimetype">
- <value>text/microsoft-resx</value>
- </resheader>
- <resheader name="version">
- <value>2.0</value>
- </resheader>
- <resheader name="reader">
- <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </resheader>
- <resheader name="writer">
- <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </resheader>
- <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
- <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
- <value>
- AAABAAYAEBAAAAAAIABoBAAAZgAAACAgAAAAACAAqBAAAM4EAAAwMAAAAAAgAKglAAB2FQAAQEAAAAAA
- IAAoQgAAHjsAAICAAAAAACAAKAgBAEZ9AAAAAAAAAAAgACggBABuhQEAKAAAABAAAAAgAAAAAQAgAAAA
- AABABAAAAAAAAAAAAAAAAAAAAAAAAF6x+yddsfzDXbH87V2y/fFcsf3xXLH88Vyy/PFdsf3xXLH98Vyx
- /PFcsfzxXLL98V2y/fFdsfztXbH8tV6x+xldsfzLXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/VKHk/1en
- 7v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfytXbL9912y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0F8
- sP9Mkc//XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL83V2y/fddsv3/XbL9/12y/f9dsv3/XLH8/0uP
- y/8nSmn/L1h9/06W1v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/OFdsv33XbL9/12y/f9dsv3/Wary/ytS
- dP8+dqj/O3Cf/0SCuf86bpz/L1l+/1uv+f9dsv3/XbL9/12y/f9csf3hXbL9912y/f9dsv3/XbL9/yxU
- d/9Voub/XbL9/0F8sP9Mkc//XbL9/0+X1v8yX4f/XbL9/12y/f9dsv3/XLH84V2y/fddsv3/XbL9/1Gb
- 3f84apb/XbL9/12y/f9BfLD/TJHP/12y/f9dsv3/MFuB/1mq8v9dsv3/XbL9/1yx/OFdsv33XbL9/12y
- /f9Aeq3/TJHO/12y/f9dsv3/QXyw/0yRz/9dsv3/XbL9/0F7r/9Lj8v/XbL9/12y/f9csf3hXbL9912y
- /f9dsv3/RIG3/0eIwf9dsv3/XbL9/0F8sP9Mkc//XbL9/12y/f88c6P/T5fW/12y/f9dsv3/XLH94V2y
- /fddsv3/XbL9/1ip8f8uV3z/XbL9/12y/f9BfLD/TJHP/12y/f9csfz/KlBy/1yx+/9dsv3/XbL9/1yx
- /OFdsv33XbL9/12y/f9dsv3/PHKh/z94q/9dsv3/QXyw/0yRz/9csfz/N2iT/0SCuf9dsv3/XbL9/12y
- /f9csfzhXbL9912y/f9dsv3/XbL9/12y/f9Aeq7/LFN1/yREYP8pTm//K1J0/0aHv/9dsv3/XbL9/12y
- /f9dsv3/XLH94V2y/fddsv3/XbL9/12y/f9dsv3/XbL9/1yx/P8+dqj/SYzH/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/OFdsv33U6Dj/y1Vef8tVXn/LVV5/y1Vef8tVXn/IT9Z/yZIZf8tVXn/LVV5/y1V
- ef8tVXn/LVV5/1mr8/9dsvzdXbH8y12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbH8rV2x+yddsfzDXbL871yx/PFcsfzzXLH981yx/fNcsf3zXbL881yy
- /PNdsvzxXLH88V2y/fFdsfzvXbH8tV6x+xkAAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA
- //8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//KAAAACAAAABAAAAAAQAgAAAAAACAEAAAAAAAAAAA
- AAAAAAAAAAAAAP///wH///8BXbH7UV6x+71csfzXXbL94V2y/eFdsvzjXLL941yx/ONcsfzjXLH8412x
- /ONcsv3jXLH9412x/eNdsf3jXLH941yy/ONcsfzjXLH841yx/ONcsv3jXLL9412y/ONdsv3hXbH8312x
- /NNesfurXrH7Mf///wH///8B////AV6x+5ddsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsfz7XrH7Xf///wFdsfxdXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfz3XrH7J16x+9Ndsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zpunP9IicP/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9esfuVXbL9712y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/JUZj/ztxof9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/Lddsv3vXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8lRmP/O3Gh/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9wV2y
- /e9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/yVG
- Y/87caH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3BXbL9712y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/SYvG/ylN
- bf8VJjX/BwsO/woRF/8YLT//MFuA/1Gb3f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/MNdsv3vXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/U5/i/x44
- T/8PGyX/Ml+H/0mMx/8hPlf/NGKL/0WEu/8rUXL/ChEY/yxTdf9arPT/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLH9w12y/e9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/02T
- 0f8MFBz/MFyC/1qt9/9dsv3/XbL9/yVGY/87caH/XbL9/12y/f9Vo+j/IT1W/xYoOf9YqO//XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csf3FXbL9712y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Wper/Dhgi/z1zpP9dsv3/XbL9/12y/f9dsv3/JUZj/ztxof9dsv3/XbL9/12y/f9csfz/J0po/x02
- Tf9csfv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/MVdsv3vXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/yVGY/8pTm7/XbL9/12y/f9dsv3/XbL9/12y/f8lRmP/O3Gh/12y/f9dsv3/XbL9/12y
- /f9brvj/FSY1/ztxoP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8xV2y/e9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9ToOP/CQ4U/1en7f9dsv3/XbL9/12y/f9dsv3/XbL9/yVGY/87caH/XbL9/12y
- /f9dsv3/XbL9/12y/f9Fhbz/ER8r/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfzFXbL9712y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/zhql/8jQVz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/JUZj/ztx
- of9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P8NFyD/TpXU/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy
- /cVdsv3vXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Jkhm/zdplf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8lRmP/O3Gh/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/yE+V/88c6P/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH9xV2y/e9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8gO1P/P3iq/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/yVGY/87caH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/KU1s/zZmkf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsf3FXbL9712y/f9dsv3/XbL9/12y/f9dsv3/XbL9/yNCXv86b57/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/JUZj/ztxof9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8kRGD/OW2b/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/cVdsv3vXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Ml+H/ylO
- b/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8lRmP/O3Gh/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/xMj
- Mf9IisT/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH9xV2y/e9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Mks//DRcg/1uv+f9dsv3/XbL9/12y/f9dsv3/XbL9/yVGY/87caH/XbL9/12y/f9dsv3/XbL9/12y
- /f9PmNj/ChIY/1uu+P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csv3FXbL9712y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx/P8YLT//OGuY/12y/f9dsv3/XbL9/12y/f9dsv3/JUZj/ztxof9dsv3/XbL9/12y
- /f9dsv3/XLH8/yJAW/8uV3z/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/MVdsv3vXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0yRz/8KERf/TZPR/12y/f9dsv3/XbL9/12y/f8lRmP/O3Gh/12y
- /f9dsv3/XbL9/12y/f87caD/Dxsm/1ip8f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8xV2y
- /e9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zxzo/8MFR3/R4jC/12y/f9dsv3/XbL9/yVG
- Y/87caH/XbL9/12y/f9csfz/OGuY/wsSGf9Nk9L/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csfzFXbL9712y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0F9sf8MFBz/JEVh/0qO
- yf9csfv/JUZj/ztxof9arfb/Qn+0/xkuQP8UJTP/TpbV/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x/cVdsv3vXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1en
- 7v8wXIL/EB4p/wgNEf8HDBD/ChAW/wYKDf8XKzz/Om+e/1uv+f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLL9w12y/e9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfz/Vqbs/yA8Vf80Yov/Wavz/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvzDXbL9712y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/JUZj/ztxof9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/cFdsv3vXbL9/12y/f9Xp+3/TpXU/06V
- 1P9OldT/TpXU/06V1P9OldT/TpXU/06V1P9OldT/TpXU/06V1P8gO1T/Ml+H/06V1P9OldT/TpXU/06V
- 1P9OldT/TpXU/06V1P9OldT/TpXU/06V1P9OldT/Wq73/12y/f9dsv3/XbL9wV2y/e9dsv3/XbL9/z52
- p/8MFR3/DBUd/wwVHf8MFR3/DBUd/wwVHf8MFR3/DBUd/wwVHf8MFR3/DBUd/wwVHf8MFR3/DBUd/wwV
- Hf8MFR3/DBUd/wwVHf8MFR3/DBUd/wwVHf8MFR3/DBUd/wwVHf9RnN7/XbL9/12y/f9dsfy3XrH7012y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/16x
- +5VdsfxdXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsfz3XrH7J////wFdsfyVXbL8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbH8+16x+13///8B////Af///wFesftTXbH8u12x/N9csvzhXLH841yy/OVcsvzlXLH951yx
- /eddsv3nXbL951yx/edcsf3nXLL951yy/OVdsfzlXbL85Vyx/eVdsv3lXbL85Vyx/ONcsf3jXbL8412y
- /eFdsv3hXbH8216x+6ldsfwv////Af///wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAwAAAAYAAAAAEAIAAAAAAAgCUAAAAA
- AAAAAAAAAAAAAAAAAAD///8B////Af///wFisPYFYLH4XV6x+6tcsfy/XbH8zV2y/dFdsv3TXbH9012y
- /NVcsvzVXLH91Vyx/NVcsfzVXLH81Vyx/NVcsfzVXbL81Vyy/dVcsf3VXbH91V2y/dVdsf3VXbH91Vyx
- /dVcsv3VXbL81Vyx/NVcsfzVXLH81Vyx/NVcsv3VXbL91Vyy/NVcsvzTXbL9012y/dFdsv3RXbH8yV2y
- /LtfsfqXYLH5Mf///wH///8B////Af///wH///8B////AV+x+i9dsfzRXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbH8/V2x+5tisfcL////Af///wH///8BYLH5NV2x/PFdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9esfu/ZLH0Cf///wFgsfkLXbH83V2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH8if//
- /wFfsfp1XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbH892Sx9B9esfvRXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/w4aJP8uVnr/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1+x+nNdsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woR
- F/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/I9dsv3nXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/J1dsv3nXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /aNdsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/aNdsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uv+f9OldT/Qn+0/wcMEP8eN07/Roa//1Sg
- 5P9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/aVdsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P9Ii8X/JUVh/woQFv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDBP8SIS7/MVyD/1Wi5/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/KVdsv3nXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/UZzd/x45UP8DAwP/CQ8U/yVF
- Yf88c6P/SYvG/wkOE/8kQ17/RYO7/zVkjv8aMET/BAUG/wcLD/8yX4b/Wq73/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Kddsv3nXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P8+dqf/BwwQ/wcM
- EP8zYYr/Wary/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/T5jY/yA8Vf8DAwP/FSY1/1Gc
- 3v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx
- /addsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zlt
- m/8DBAT/GCw+/1Kd4P9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/1yx
- /P9Ae6//CA4T/wwVHv9RnN3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yy/addsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/RYS8/wQGB/8cNEn/Wq32/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/TJLQ/wgOE/8SIS7/WKnx/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Kddsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9Wpev/CxQb/xEfK/9YqO//XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woR
- F/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0SCuf8DBAX/Jkhm/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Kddsv3nXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8pTm//BAUG/0uPy/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8rUXL/AwQE/0qN
- yf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Kddsv3nXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1al6/8GCQz/JERg/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Xp+7/CA4T/yE9V/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx
- /Kddsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zlsmv8DAwP/So3J/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/KU1t/wUICv9Xp+7/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/Kddsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/yA7
- VP8NFyD/XLH7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/RoW9/wMDA/9BfLD/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy/addsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/w4ZIv8hPlj/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woR
- F/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Wary/wQFB/8vWX7/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/addsv3nXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/W6/5/wUHCf8tVXj/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wwV
- HP8lRWL/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/addsv3nXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Waz0/wQFBv8wW4L/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/w8bJv8iP1r/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x
- /addsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W6/6/wUIC/8sU3b/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8lR2T/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x/addsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/w8c
- Jv8fO1P/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6fu/wMEBf8wXIL/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/addsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/yJAWv8LExr/XLD6/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woR
- F/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Q4C2/wMDA/9DgLb/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/addsv3nXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/zxyov8DAwP/Roe//12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/JUZj/wcL
- Dv9ZqvL/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy/addsv3nXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1ip8P8IDRH/HztT/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Uoub/BgoN/yREYf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /Kddsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8uV3z/AwME/0WF
- vP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx/P8lRWL/BAUH/06V0/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx/Kddsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9YqfH/Dxol/w0XH/9Vouf/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/z51p/8DAwP/LFN1/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Kddsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/So7J/wYJC/8WKDj/V6fu/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woR
- F/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Roa//wYJC/8XKjv/Wq32/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Kddsv3nXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0B6rf8EBgf/ER8s/0yRzv9dsv3/XbL9/12y
- /f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/1yx+/83aZX/BQgK/xAdKf9Vouf/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Kddsv3nXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Eg7r/CxMZ/wQG
- CP8qT3D/VKHl/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9csfz/R4jB/xcrPf8DAwP/GzJH/1Wj
- 6P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy
- /Kddsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/VqTp/yZIZv8EBQb/BAYI/xszSP8zYIn/P3ms/wgNEf8fO1P/O3Gh/ytSdf8RHir/AwMD/wsT
- Gv86bpz/XLD7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx/addsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9PmNj/LVV4/xEeKv8DBAT/AwMD/wMDA/8DAwP/AwMD/wUI
- Cv8aMUX/OWyZ/1iq8f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy/Kddsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P9Wpev/S5DN/wgN
- Ev8iP1n/T5jX/1qs9f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/KVdsv3nXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/aVdsv3nXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /aNdsv3nXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/woRF/8rUXP/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/aNdsv3nXbL9/12y/f9dsv3/XbL9/zZnkv8aL0P/Gi9D/xovQ/8aL0P/Gi9D/xov
- Q/8aL0P/Gi9D/xovQ/8aL0P/Gi9D/xovQ/8aL0P/Gi9D/xovQ/8aL0P/Gi9D/wQGCP8NFx//Gi9D/xov
- Q/8aL0P/Gi9D/xovQ/8aL0P/Gi9D/xovQ/8aL0P/Gi9D/xovQ/8aL0P/Gi9D/xovQ/8aL0P/Gi9D/xov
- Q/9Pl9b/XbL9/12y/f9dsv3/XbL9/12x/J1dsv3nXbL9/12y/f9dsv3/XbL9/zFdhP8RHyv/ER8r/xEf
- K/8RHyv/ER8r/xEfK/8RHyv/ER8r/xEfK/8RHyv/ER8r/xEfK/8RHyv/ER8r/xEfK/8RHyv/ER8r/xEf
- K/8RHyv/ER8r/xEfK/8RHyv/ER8r/xEfK/8RHyv/ER8r/xEfK/8RHyv/ER8r/xEfK/8RHyv/ER8r/xEf
- K/8RHyv/ER8r/xEfK/9Nk9H/XbL9/12y/f9dsv3/XbL9/12y/Y9esfvRXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1+x+nNfsfp1XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH892Sx
- 9B9gsfkLXbH83V2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbH8if///wH///8BX7H6M12x/PFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9esfu/ZLH1Cf///wH///8B////AV+x+S9dsfzVXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbH8/V2x+5ljsfYL////Af///wH///8B////Af///wFpsO8FX7H6W16x
- +61dsfzPXbH80Vyy/dNcsfzVXbL911yx/NlcsvzZXLL92V2x/dtcsf3bXbL9212y/dtdsv3bXLH921yx
- /dtcsf3bXLH92V2y/dlcsv3ZXbH82V2x/Nldsv3ZXLH82Vyx/dddsfzXXbL9112x/NddsfzXXLH91Vyx
- /dVcsvzVXbL9012y/dNdsv3RXbL9z12x/MNfsfqXXrH7Lf///wH///8B////Af///wEAAAAAAAD//wAA
- AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA
- //8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA
- AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA
- //8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA
- AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA
- //8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA
- AAAAAP//AAAAAAAA//8oAAAAQAAAAIAAAAABACAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAA////Af//
- /wH///8B////Af///wFpr+8JZLH0X12x/JVcsvynXbH8t12y/cFdsv3BXbL9w12x/cVcsvzFXbL9x1yx
- /Mddsv3HXLH9x12x/MdcsfzHXLH8x1yx/MdcsfzHXLH8x12y/MdcsvzHXLL9x1yx/cddsf3HXbH9x12y
- /cddsf3HXbH9x12x/cdcsf3HXLL9x12y/MddsvzHXLH8x1yx/MdcsfzHXLH8x1yx/MdcsvzHXLH9x1yy
- /cdcsfzHXLL8xV2y/cVdsv3DXbL8w12y/cFcsfy9XLH8r12y/KFgsfmBaLDxLf///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wFesftZXbH8312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x
- /P1dsfylYLH5G////wH///8B////Af///wH///8B////AWqw7glesfulXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/OtgsflD////Af///wH///8B////AW6w6gNesfutXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH89WCx+T3///8B////Af//
- /wFesftxXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsfzjYbH4Ef///wFgsfkVXbH88V2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/If///8BYbH3hV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6fu/0WFvP9MkM3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfz1dK/iE16x+8tdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/2Cx
- +U1dsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9IisT/AwMD/xoxRf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsvxnXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH8dV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/IFdsv3fXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9IisT/AwMD/xox
- Rf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv2DXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL8hV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/YVdsv3fXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1mq8v9CfrP/LVZ6/yE9V/8TIzD/AwMD/wgMEP8bM0j/Jkhn/zZn
- kv9Pl9b/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv2HXbL9312y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/SIvF/yJAWv8HCw7/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/xIgLf80Yoz/WKjv/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8h12y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Rmtv/HzpS/wMDBP8DAwP/BAUG/xcq
- O/8vWX7/PXSl/zdolP8DAwP/FSY2/0J/tP83aJT/JERg/wsSGf8DAwP/AwMD/wsSGf85bJn/W7D6/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Ildsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx+/82aJP/BgoO/wMD
- A/8HDBH/L1h9/1Ke4P9csfz/XbL9/12y/f9IisT/AwMD/xoxRf9dsv3/XbL9/12y/f9brvj/Q3+1/xku
- QP8DAwP/AwMD/xgsPv9Rm9z/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csv2JXbL9312y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1qt
- 9/8iQVz/AwMD/wMDA/8jQl3/VKHl/12y/f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfz/P3ms/wwVHf8DAwP/CQ8V/0aGv/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH9iV2y
- /d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yw+v8hPlf/AwMD/wcMEP8/eKv/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iK
- xP8DAwP/GjFF/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Wpev/HjhP/wMDA/8GCg3/SYvF/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yy/Ildsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/P8tVXn/AwMD/wgNEv9Kjcn/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9IisT/AwMD/xoxRf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uv
- +f8kRGH/AwMD/woRGP9RnN7/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfyJXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9CfrP/AwQE/wQGB/9Egrj/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/W674/xsyR/8DAwP/Fik6/1uu+P9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8iV2y/d9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9XqO7/DBUd/wMD
- A/8yXob/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9WpOn/DBYe/wMDA/8zYYr/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx
- /Ildsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/Llh9/wMDA/8VJzb/W6/5/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9IisT/AwMD/xoxRf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0J+
- sv8DAwP/CA0R/1Wk6f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfyJXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/WKrx/wkPFP8DAwP/Roa//12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfz/GjBE/wMDA/8xXYP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8iV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zxzo/8DAwP/FSY2/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0J/tP8DAwP/Dxsl/1yw+/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/Ildsv3fXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8fOlL/AwMD/zZm
- kf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9IisT/AwMD/xox
- Rf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9br/n/CxMa/wMD
- A/9LkM3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsvyJXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9br/n/CQ8V/wMDA/9Qmtv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/yREYP8DAwP/NGKM/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLL9iV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/UJna/wMDA/8LFBv/XLD7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f85bJn/AwMD/yJAWv9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Yldsv3fXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0SCuP8DAwP/GS5A/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9IisT/AwMD/xoxRf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/RofA/wMDA/8WKDn/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsf2JXbL9312y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f89dab/AwMD/yA8
- Vf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/SIrE/wMD
- A/8aMUX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/06V
- 1P8DAwP/Dxwn/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbH9iV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/PHOj/wMDA/8hP1n/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9PmNj/AwMD/w4ZI/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/Yldsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0B6rf8DAwP/HTdN/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9IisT/AwMD/xoxRf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/S5DN/wMDA/8SIC3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsf2JXbL9312y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Ji8b/AwMD/xMiMP9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0F8r/8DAwP/GzJH/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH9iV2y
- /d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Vqbs/wQF
- Bv8FCAv/Wavz/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iK
- xP8DAwP/GjFF/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8wW4D/AwMD/ypPcP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x/Yldsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx/P8SIS7/AwMD/0WDuv9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9IisT/AwMD/xoxRf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfz/GC1A/wMDA/8+dqj/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csf2JXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/LFN2/wMDA/8nSWj/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/U6Dj/wQFB/8FBwn/VqTq/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLL9iV2y/d9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0uQzf8DAwP/CA0S/1eo
- 7v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zFcg/8DAwP/HjdO/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy
- /Yldsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csfz/Fyo8/wMDA/8wW4D/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9IisT/AwMD/xoxRf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1em
- 7f8JEBb/AwMD/0OAtv9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsvyJXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0SCuf8DAwP/BgkM/0+Y2P9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx/P8nSWf/AwMD/xcrPP9csfv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8iV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/IT5Y/wMDA/8VJjb/Waz0/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8/eav/AwME/wUHCP9LkM3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Ildsv3fXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1ak
- 6v8NGCH/AwMD/yJAWv9csPr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9IisT/AwMD/xox
- Rf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Kjsv/BwsP/wMDA/8zYYn/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csfyJXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/S4/M/wcLD/8DAwP/JUZj/1qt9/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9JjMf/ChEY/wMD
- A/8iP1r/XLH7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLH8iV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9DgLb/BQgL/wMDA/8XKjv/T5jY/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw
- +v81ZpD/BgkL/wMDA/8bMkf/Wqz1/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Ildsv3fXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iJ
- w/8MFR3/AwMD/wYJDP8vWX7/WKnw/12y/f9dsv3/XbL9/12y/f9IisT/AwMD/xoxRf9dsv3/XbL9/12y
- /f9dsv3/XLH8/0iKxP8WKDn/AwMD/wMDA/8mR2T/Wq31/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvyJXbL9312y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/VqTp/yNCXf8DAwT/AwMD/wkPFP8pTW7/Roa//1qu9/9dsv3/SIrE/wMD
- A/8aMUX/XbL9/1yx/P9Tn+P/OWyZ/xgtP/8DAwP/AwMD/wwVHf8/eaz/XLH8/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH9iV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/R4jB/xgsPv8DAwP/AwMD/wMD
- A/8GCg3/EiIv/xYoOf8DAwP/ChEX/xgsPv8NFh//AwME/wMDA/8DAwP/CA0R/y5Yff9YqO//XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy/Yldsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csfz/So/L/yxTdf8RHyv/AwQF/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wcMEP8eOE//Om+d/1en
- 7v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfyJXbL9312y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/1al6/9Lj8v/NGKL/wMDA/8TIjD/RoW9/1Ca
- 2v9arff/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL8h12y
- /d9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iK
- xP8DAwP/GjFF/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/Iddsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9IisT/AwMD/xoxRf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsf2FXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL8hV2y/d9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8DAwP/GjFF/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /YNdsv3fXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Roa+/z95rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95
- rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95
- rP8yXoX/AwMD/xMiL/8/eaz/P3ms/z95rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95
- rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95rP8/eaz/P3ms/z95rP8/eaz/P3ms/1Si5v9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsvyBXbL9312y/f9dsv3/XbL9/12y/f9dsv3/XbL9/xgrPf8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/9Egbj/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH9dV2y/d9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8mSGb/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYo
- OP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYo
- OP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYoOP8WKDj/Fig4/xYo
- OP8WKDj/Fig4/xYoOP8WKDj/SYzG/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/GdesfvLXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9gsflNYbH3hV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsfz1dK/iE2Cx+RVdsvzvXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH8h////wH///8BXrH7b12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH842Gx+BH///8B////AWyv
- 7ANesfurXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH89WCx
- +T3///8B////Af///wH///8BabDvCV6x+6Vdsvz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbH87WGx+EP///8B////Af///wH///8B////Af///wFtsO0DYLH5X12x/OVdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsfz7XbH8oWCx+Rv///8B////Af///wH///8B////Af///wH///8B////Af//
- /wFpsO8HYLH5U16x+5tdsfy9XbL8wV2y/MNcsvzFXLH8x1yx/clcsf3LXbL8y12y/M1csv3NXLH9zV2x
- /c1csf3PXbL9z12y/c9dsv3PXbL9z12y/c9csf3PXbH9z1yx/M1csf3NXLH9zVyy/c1csv3NXLL8zV2x
- /M1dsfzLXbL8y12y/MtcsfzLXbL9y1yx/Mtdsv3JXbL9yVyx/MldsfzJXLH8x1yy/cdcsfzHXLH8xV2y
- /cVdsv3FXbL9w12y/cNdsv3BXbL9vV2x/K1hsfiFYbH4Jf///wH///8B////Af///wH///8B////AQAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAIAAAAAAAQAAAQAgAAAAAAAACAEAAAAAAAAA
- AAAAAAAAAAAAAP///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wF/q9MDcLDnF12x/T9dsvxLXLH9V12x/GVdsfx1XbL9gV2y/YNdsf2DXLL9hV2y/Iddsv2HXbH9iV2y
- /YlcsfyLXLL8i1yy/I1dsv2NXLH8j1yy/Y9dsv2PXbL9j1yx/Y9csv2RXbL8kVyx/JFcsfyRXLH8kVyx
- /JFcsfyRXLH8kVyx/JFcsfyRXLH8kVyx/JFcsfyRXbL8kV2y/JFdsvyRXLL9kVyy/ZFcsv2RXLH9j12x
- /Y9dsf2PXbH9j12x/Y9dsf2PXbL9j12y/Y9dsv2PXbH9j12x/Y9dsf2PXbH9j12x/Y9csf2PXLL9kVyy
- /ZFcsv2RXbL8kV2y/JFdsvyRXLH8kVyx/JFcsfyRXLH8kVyx/JFcsfyRXLH8kVyx/JFcsfyRXLH8kVyx
- /JFdsvyRXLL9kVyx/Y9dsv2PXbL9j1yy/Y9csfyPXbL9jVyy/I1csvyLXLH8i12y/Yldsv2JXbL9h12y
- /Idcsv2FXbH9g12y/YNdsf2BXbH8dV2x/Gdcsf1XXbL8S12x/T9vsOgXfqzTBf///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wFpr+8dZ7DxkWKx9uVdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9isfflZ7Dxk2mv7x////8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wFhsfYXXrH7i12x
- /PNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH89V6x
- +41hsfcX////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wFmsPIFYLH5ZV2x/Otdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/O1gsflnZrHyBf///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BZLD0E1+x+q9dsvz/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9fsfqxZLD0Ff///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////AWqw7h9esfvRXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9esfvTarDuI///
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wFpsO8bX7H6112y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9fsfrZabDvHf///wH///8B////Af///wH///8B////Af//
- /wH///8BbrDqC16x+8Vdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9esfvJbbDrDf///wH///8B////Af///wH///8B////Af///wFfsfqNXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9fsfqR////Af///wH///8B////Af//
- /wH///8BYbH4OV2x/Ptdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x/Pthsfg9////Af///wH///8B////AWSu8gNdsfzDXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/Mdkr/QF////Af//
- /wH///8BYLH5TV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/2Cx+VH///8B////AYOt0gNhsfjPXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/YbH4036t
- 1wX///8Bda/hQV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/0iJwv8uWHz/Llh8/y5YfP9Hh8D/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/dK/jRf///wFjsfWDXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJf
- h/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9jsfWH////AV6x+6ldsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/16x+63///8BXbL9wV2y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMD
- A/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL8x////wFdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csvzR////AV2y/cFdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMD
- A/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x/N1dsfwDXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH87V2x/AVdsv3BXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMD
- A/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csvz5XbL8BV2y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9esv0HXbL9wV2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRi
- i/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1ux/Qddsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XrT9B12y
- /cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfwJXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/160
- /Qtdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLL9C12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsf0NXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P9Zq/P/UZvd/0SD
- uv86bpz/L1qA/xcrPP8DAwP/AwMD/wMDA/8XKjr/L1p//zlum/9Egrn/UZvc/1mr8/9csfz/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/Q1dsv3BXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/W6/5/06W1f80Y43/GjFF/wkQFv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CQ8V/xowRP80Yoz/TpXU/1uv+f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbP9D12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/UJrb/zBcgv8TIjD/AwQF/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DBAT/EiEv/zBbgf9Qmdn/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csf0PXbL9wV2y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/So7J/x87
- U/8FBwr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wUHCf8eOVH/SYzH/1yx
- /P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx+xFdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/UJrb/yJBXP8EBgj/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQF
- Bv8MFh7/Fys9/yNCXf8tVXn/HjdO/wMDA/8DAwP/AwMD/x02TP8tVXn/I0Ne/xgsPv8NFh//BAUH/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8EBgf/Ij9Z/1CZ2f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH9EV2y/cFdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Wary/zBcg/8HDBD/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/BwwQ/x03Tv84a5j/UZvc/1qt9v9dsv3/XbL9/12y/f80Yov/AwMD/wMD
- A/8DAwP/Ml+H/12y/f9dsv3/XbL9/1qt9/9Rm93/OWya/x44T/8HDBD/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/BwsP/y9agP9YqvH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfsRXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8/0iKxP8SIi//AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/Fyo8/zpvnv9WpOr/XLH8/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8/1al6/87cKD/GCw+/wMDBP8DAwP/AwMD/wMDA/8DAwP/AwMD/xIgLf9HiMH/XLH8/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/hNdsv3BXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uv+P8wXIL/BQcK/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/Fio7/0WFvP9csPr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMD
- A/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPr/Roa//xcr
- Pf8DAwP/AwMD/wMDA/8DAwP/AwMD/wUHCf8vWX//W673/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLH+E12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Xp+3/HTdN/wMDA/8DAwP/AwMD/wMDA/8DAwP/DBYe/zxzpP9br/n/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W6/5/z11pv8NFx//AwMD/wMDA/8DAwP/AwMD/wMD
- A/8cNUr/VqXr/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsf4TXbL9wV2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/VKHm/xMkM/8DAwP/AwMD/wMDA/8DAwP/AwQF/ydK
- aP9Xpuz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRi
- i/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1en7v8oTGz/AwQF/wMDA/8DAwP/AwMD/wMDA/8TIjD/U6Dj/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/hNdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1al
- 6/8SIS7/AwMD/wMDA/8DAwP/AwMD/wsTGv9Df7X/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P9Egbj/CxQc/wMD
- A/8DAwP/AwMD/wMDA/8RHyz/VaTp/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLL9E12y
- /cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9arPT/GS5A/wMDA/8DAwP/AwMD/wMDA/8WKDj/Up3g/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Tn+L/Fyo7/wMDA/8DAwP/AwMD/wMDA/8XKz3/Wavz/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvsTXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7/yNB
- Xf8DAwP/AwMD/wMDA/8DAwP/GzNI/1io7/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9YqfD/HDZM/wMDA/8DAwP/AwMD/wMDA/8hPlj/XLD6/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw
- +xVdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/P8zYYn/AwMD/wMDA/8DAwP/AwMD/xgsP/9YqfH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9ZqvL/GS9C/wMDA/8DAwP/AwMD/wMD
- A/8xXoX/XbH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7FV2y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Roa//wUH
- Cf8DAwP/AwMD/wMDA/8QHir/VaLn/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9VpOn/EiAt/wMDA/8DAwP/AwMD/wQGCP9FhLz/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csPsVXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1am7P8PGiX/AwMD/wMDA/8DAwP/CQ8U/06V1P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Pl9b/CRAW/wMD
- A/8DAwP/AwMD/w0YIf9Wper/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+xVdsv3BXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/J0pp/wMD
- A/8DAwP/AwMD/wMEBf8/eaz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJf
- h/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9BfLD/BAUG/wMDA/8DAwP/AwMD/yVGZP9csfz/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLD7FV2y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0iKxP8EBgj/AwMD/wMDA/8DAwP/J0pq/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx
- /P8pTm7/AwMD/wMDA/8DAwP/BAUH/0eHwP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsVXbL9wV2y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9br/n/GC1A/wMD
- A/8DAwP/AwMD/w4ZI/9YqfD/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMD
- A/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1iq8f8PHCf/AwMD/wMDA/8DAwP/Fyo7/1uv
- +f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yw+xVdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0J/tf8DBAT/AwMD/wMDA/8DAwP/QXyw/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/0N/tf8DAwP/AwMD/wMDA/8DAwT/QXyw/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7FV2y/cFdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfv/GjBE/wMD
- A/8DAwP/AwMD/xowRP9csPv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMD
- A/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/xszR/8DAwP/AwMD/wMD
- A/8YLT//XLH7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csPsVXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/02T0f8EBQf/AwMD/wMDA/8DAwP/Roe//12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/SIrE/wMDA/8DAwP/AwMD/wQFBv9LkM3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+xVdsv3BXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/LFN2/wMD
- A/8DAwP/AwMD/xYoOP9csPr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMD
- A/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPv/Fys8/wMD
- A/8DAwP/AwMD/ypQcf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL7E12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1qt9v8OGSP/AwMD/wMDA/8DAwP/OWya/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f86b57/AwMD/wMDA/8DAwP/DRcg/1qs9f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvsTXbL9wV2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/SYvG/wMD
- A/8DAwP/AwMD/wcLDv9WpOr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRi
- i/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1en
- 7f8HDBD/AwMD/wMDA/8DAwP/R4jB/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y+xNdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8vWH3/AwMD/wMDA/8DAwP/HjhP/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/x87U/8DAwP/AwMD/wMDA/8tVXj/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLL9E12y
- /cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/xcr
- Pf8DAwP/AwMD/wMDA/84bJn/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/Om+e/wMDA/8DAwP/AwMD/xYoOP9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9bsv4TXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9XqO//CA0R/wMDA/8DAwP/AwQE/0+Y2f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Rm93/AwQE/wMDA/8DAwP/BwsP/1am
- 6/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uy
- /hNdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0uP
- zP8DAwP/AwMD/wMDA/8NFx//Wq32/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1uu+P8OGSP/AwMD/wMDA/8DAwP/SYzH/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH+E12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/PHKi/wMDA/8DAwP/AwMD/xszSP9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/x03Tf8DAwP/AwMD/wMD
- A/86b53/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsP4TXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8wW4D/AwMD/wMDA/8DAwP/KU5v/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/K1F0/wMDA/8DAwP/AwMD/y5XfP9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/hNdsv3BXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/yZJZ/8DAwP/AwMD/wMDA/80Y43/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJf
- h/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f82Z5L/AwMD/wMD
- A/8DAwP/JUVi/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbD+E12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/IDxV/wMDA/8DAwP/AwMD/zxyov9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/z51p/8DAwP/AwMD/wMDA/8eOVD/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsP4TXbL9wV2y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8cNUr/AwMD/wMDA/8DAwP/QHqt/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMD
- A/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/QX2y/wMD
- A/8DAwP/AwMD/xoxRv9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12w/hNdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/xszSP8DAwP/AwMD/wMDA/9BfLH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9DgLb/AwMD/wMDA/8DAwP/GS9D/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbD+E12y/cFdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/HDRK/wMDA/8DAwP/AwMD/0B6
- rv9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMD
- A/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0F9
- s/8DAwP/AwMD/wMDA/8aMUX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsP4TXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8gO1T/AwMD/wMDA/8DAwP/PHOj/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Pnan/wMDA/8DAwP/AwMD/x44T/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/hNdsv3BXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/yZIZv8DAwP/AwMD/wMD
- A/81ZI7/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMD
- A/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f82aJP/AwMD/wMDA/8DAwP/JEVh/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbD+E12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/L1l//wMDA/8DAwP/AwMD/ypPcf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/yxTdf8DAwP/AwMD/wMDA/8tVnr/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsP4TXbL9wV2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f87caD/AwMD/wMD
- A/8DAwP/HDVL/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRi
- i/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/HjhP/wMDA/8DAwP/AwMD/zltm/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/hNdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0qNyf8DAwP/AwMD/wMDA/8NGCH/Wq73/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uu+P8PGiX/AwMD/wMDA/8DAwP/SIrE/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbD+E12y
- /cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6ft/wcL
- D/8DAwP/AwMD/wMEBf9Qmtv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/Up3g/wMEBf8DAwP/AwMD/wYKDv9WpOr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsP4TXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/Fik5/wMDA/8DAwP/AwMD/zpunf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f87cqL/AwMD/wMDA/8DAwP/FCU1/1yx
- +/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w
- /hNdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8tVXn/AwMD/wMDA/8DAwP/HztT/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8/yE+WP8DAwP/AwMD/wMDA/8rUnT/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH+E12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0eIwf8DAwP/AwMD/wMDA/8IDRH/Vqbs/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9YqO//CA4T/wMDA/8DAwP/AwMD/0WE
- vP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9bsv4TXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/Waz0/w0WH/8DAwP/AwMD/wMDA/87cJ//XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/zxzpP8DAwP/AwMD/wMDA/8MFBz/Warz/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uy/hNdsv3BXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/KU5v/wMDA/8DAwP/AwMD/xgs
- Pv9csPv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJf
- h/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfv/GS9C/wMDA/8DAwP/AwMD/yhL
- av9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/W7L+E12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9Kj8v/AwQF/wMDA/8DAwP/AwME/0mLxv9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/0qOy/8DAwT/AwMD/wMDA/8DBAX/SYzH/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvsTXbL9wV2y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+/8XKzz/AwMD/wMD
- A/8DAwP/HDVL/1yx+/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMD
- A/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/HjhP/wMDA/8DAwP/AwMD/xUo
- OP9csPr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y+xNdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/z96rf8DAwP/AwMD/wMDA/8DAwP/RIK4/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/0WFvf8DAwP/AwMD/wMDA/8DAwP/Pnao/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL7E12y/cFdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W674/xUn
- N/8DAwP/AwMD/wMDA/8QHSn/Wav0/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMD
- A/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9arPX/ESAs/wMDA/8DAwP/AwMD/xMk
- M/9brvf/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csPsTXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/RYO6/wQFBv8DAwP/AwMD/wMDA/8rUXP/XLH8/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8/yxVeP8DAwP/AwMD/wMDA/8DBAX/Q4C2/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+xVdsv3BXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csfz/IkFc/wMDA/8DAwP/AwMD/wQFBv9DgLb/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMD
- A/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Egrn/BAYH/wMDA/8DAwP/AwMD/yE+
- V/9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLD7FV2y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9UoeX/DBUd/wMDA/8DAwP/AwMD/woS
- GP9Qmtv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/UZvd/wsUG/8DAwP/AwMD/wMDA/8LExr/U6Dk/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsVXbL9wV2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9BfbL/BAUH/wMDA/8DAwP/AwMD/xMjMf9Wpuz/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRi
- i/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1en7f8UJjX/AwMD/wMDA/8DAwP/BAUF/0B7
- rv9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+xVdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P8tVXn/AwMD/wMD
- A/8DAwP/AwMD/xszSP9Zq/P/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9ZrPT/HTZM/wMDA/8DAwP/AwMD/wMDA/8rUnT/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7FV2y
- /cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1uu+P8dNk3/AwMD/wMDA/8DAwP/AwMD/x87VP9ZqvL/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Wavz/yE+V/8DAwP/AwMD/wMDA/8DAwP/GzNI/1uu
- 9/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsVXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1en
- 7v8UJDP/AwMD/wMDA/8DAwP/AwMD/xowQ/9UoeX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1Wi
- 5/8bMkb/AwMD/wMDA/8DAwP/AwMD/xMiMP9Wpuz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw
- +xVdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1Ke4f8OGSL/AwMD/wMDA/8DAwP/AwMD/w4Z
- I/9Gh8D/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9HicL/Dxsl/wMDA/8DAwP/AwMD/wMDA/8NFyH/UZze/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7FV2y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1CZ2f8OGiT/AwMD/wMDA/8DAwP/AwMD/wUHCf8sVHf/Wary/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Zq/P/LVZ6/wUH
- Cf8DAwP/AwMD/wMDA/8DAwP/Dhki/0+X1v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csPsVXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1Of4/8WKTn/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8PHCf/QX2x/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfz/Qn+0/xAdKf8DAwP/AwMD/wMDA/8DAwP/AwMD/xUnN/9SnuD/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y+xNdsv3BXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1mr9P8nS2r/AwQE/wMDA/8DAwP/AwMD/wMDA/8DAwP/GzJG/0qO
- y/9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJf
- h/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/S5DN/xszSP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDBP8mSGb/Wary/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL8E12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx
- /P9BfLD/DBUe/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/xszSP8/eaz/Wavz/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx
- /P9Zq/T/QHqu/xw0Sv8DAwT/AwMD/wMDA/8DAwP/AwMD/wMDA/8MFBz/QHqt/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csf4TXbL9wV2y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Wper/J0pp/wQGCP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8JDxT/I0Fc/z11p/9VpOn/W7D6/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMD
- A/8yX4f/XbL9/12y/f9dsv3/XLD6/1ak6v8+dqj/I0Jd/wkQFf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8EBgj/Jkhn/1Wk6f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x/hNdsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/So7K/xowRP8DBAT/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQG
- CP8QHSn/HDVL/yhMbP8yX4f/IT1W/wMDA/8DAwP/AwMD/yA7U/8yX4j/KU1s/x02TP8RHir/BAYI/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DBAT/GS9C/0mNyP9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH+E12y/cFdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7/0J/
- tP8XKzz/AwQF/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DBAX/Fik6/0J9
- sv9csPv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv4TXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+/9JjMf/KEtr/wwVHv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8MFR3/J0pp/0iKxf9csPv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy+xFdsv3BXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/Waz0/0eHwP8sVHf/EyMw/wYKDf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgkM/xIiL/8sU3b/Roa//1mr9P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLH9EV2y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csPv/VaPo/0qOyv8+dqj/NGKM/ypPcf8UJTT/AwMD/wMDA/8DAwP/FCQy/ypPcP8zYov/Pnan/0qO
- yf9Vo+f/XLD7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvwRXbL9wV2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRi
- i/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/A9dsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLL8D12y
- /cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv0PXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x
- /Q1dsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJfh/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH9C12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9etP0LXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/zRii/8DAwP/AwMD/wMDA/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Aldsv3BXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGKL/wMDA/8DAwP/AwMD/zJf
- h/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XrT9B12y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f80Yov/AwMD/wMDA/8DAwP/Ml+H/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9bsf0HXbL9wV2y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zRii/8DAwP/AwMD/wMD
- A/8yX4f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/16y/Qddsv3BXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/z11pv8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJA
- W/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJA
- W/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJA
- W/8iQFv/IkBb/yJAW/8iQFv/FCQz/wMDA/8DAwP/AwMD/xMjMf8iQFv/IkBb/yJAW/8iQFv/IkBb/yJA
- W/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJA
- W/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJA
- W/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/IkBb/yJAW/8iQFv/PHOj/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csvz5XbL8BV2y/cFdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/LVR3/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8rUXP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x/O1dsfwFXbL9wV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8tVHf/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/ytRc/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH93Vyx/QNdsv3BXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/y1Ud/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/K1Fz/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csvzR////AV2y/cFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/QXyw/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylO
- bv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylO
- bv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylO
- bv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylO
- bv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylO
- bv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylO
- bv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv8pTm7/KU5u/ylObv9Aeq7/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/Mf///8BXrH7qV2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XrH7rf///wFjsfWDXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9jsfWH////AXWv
- 4UFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/3Sv40X///8Bg63SA2Gx+M9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9hsfjTfq3XBf//
- /wH///8BYLH5TV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/2Cx+VH///8B////Af///wFksPIDXbL8w12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfzHZK/0Bf//
- /wH///8B////Af///wFgsfk3XbH8+12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbH8+2Cx+D3///8B////Af///wH///8B////Af///wFesfqHXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9fsfqP////Af//
- /wH///8B////Af///wH///8B////AWyv7Alesfu/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XrH7x22w7Av///8B////Af///wH///8B////Af///wH///8B////AWWw
- 8xdesfvTXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1+x+tlosfEd////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////AWmw7x1esfvPXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9esfrVarDuI////wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////AWWx8xNgsfmzXbL8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvz/YLH5t2ew8hf///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AW2w7QVisfdvXrH78V2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL86WCx+WVpsO4F////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wFosPEfYLH4m12x/Pddsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH88V6x/IlgsfkV////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8BabDvHWGx93tfsfrTXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/YLH43WCx
- +HlksfUV////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AXWw4gNur+kdYrH2U12x
- /HVdsfyDXbL9g1yy/IVdsvyHXbL9iVyy/YtcsfyNXLL9j1yx/JFcsfyTXbL9lV2y/JVcsf2XXLL9l12x
- /JldsfyZXLL8m1yy/Jtcsv2bXLH9m1yx/Z1csfydXbL9nVyx/Z1csfydXbL9nV2y/Z1dsv2dXbL9nV2y
- /Z1dsv2dXbL9nV2y/Z1dsv2dXbL9nVyx/Z1csf2dXLH9nV2y/Z1csf2dXLH9nVyx/J1csf2dXLH9m12x
- /Ztdsv2bXbL8m1yy/Jtdsv2bXLL8m1yy/JldsfyZXbH9mV2x/ZldsfyZXLH8mV2y/Zldsv2XXLL8l1yx
- /JdcsfyXXbH9l1yy/ZddsvyVXLH8lV2y/ZVdsv2VXLH9lV2y/JNdsfyTXLL8k12x/JNdsfyRXLH8kVyx
- /JFcsf2PXbL9j1yy/I9csf2NXbL8jVyx/I1dsv2LXbL9i12x/Yldsv2JXLL9h12y/Yddsv2FXbL9hV2y
- /YNdsv2DXbL9gV2y/XVdsfxlYrH2UXav4TF/rdYD////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAQAAAAIAAAEAIAAAAAAAACAEAAAA
- AAAAAAAAAAAAAAAAAAD///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8BXLL8A1yx/QNcsf0DXbH8A12x/AVdsvwFXLL8BV2x
- /QVhsv0HWrT9B1ut/QlgtP0JXbb9C1yv/gtdsvkNXrT9D162/g9bsP4RX7L+E1yw/hNesf4VXrP+FVyx
- +xdbsvsXXbP9GVuw+hlcsf4bXbL7G16z/Rtdsv4dWrD7HVyx+h1csvsfXLP+H16y/h9csf4fXLL+H12y
- /iFdsP4hXLH+IVuy/iFcsv0hXbL7IV2y+yFcsfshXLD7I1yw+yNcsPsjXLD7I1yw+yNcsPsjXLD7I1uw
- +yNbsfsjW7H7I1ux+yNbsPsjXLD7I1yw+yNcsPsjXLD7I1yw+yNcsPsjXLD7I1yw+yNdsvshXbL7IV2y
- +yFdsvshXbL7IV2y+yFdsvshXLL9IVuy/iFbsv4hW7L+IVuy/iFbsv4hW7H+IV2w/iFdsP4hXbD+IV2w
- /iFdsP4hXbD+IV2w/iFdsP4hXbD+IV2w/iFdsP4hXbL+IV2y/iFdsv4hXbL+IV2y/iFdsf4hXbD+IV2w
- /iFdsP4hXbD+IV2w/iFdsP4hXbD+IV2w/iFdsP4hXbD+IV2w/iFbsf4hW7L+IVuy/iFbsv4hW7L+IVuy
- /iFcsv0hXbL7IV2y+yFdsvshXbL7IV2y+yFdsvshXbL7IVyw+yNcsPsjXLD7I1yw+yNcsPsjXLD7I1yw
- +yNcsPsjW7D7I1ux+yNbsfsjW7H7I1uw+yNcsPsjXLD7I1yw+yNcsPsjXLD7I1yw+yNcsPsjXLH7IV2y
- +yFdsvshXLL8IVuy/iFcsf4hXbD+IV2y/iFcsv4fXLH+H16y/h9ds/4fXLL7H1yx+h1asPsdXbL+HV6z
- /RtdsvobXLH+G1yx+hlds/0ZW7L7F1yx+xdes/4VXrH+FVyw/hNdtf4RW7D+EV62/g9etP4PXbL5DVyv
- /gtdtv0LYLX9CVyt/QlZtP0HYrL9B12x/QVdsv0FXbL8BV2x/AVdsfwDXbH8A1yx/QNcsvwD////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wGaqLQDeKzaC3mu2hlsse09XbH9b12y/IldsvyPXbL8mVyy/KVcsf2zXLH8wV2x/M9csfzfXbL87V2y
- /ftdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9+12y/O1csfzfXbH80V2x/cFcsf2zXLL8pV2y
- /ZldsvyPXbL8iV2x/XFqse4/ea7aG3is2guYqbgD////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AX+t
- 1w2ErtJdbK/rpWew8e9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9nsPLxbK/sqYOu1GGBrdUP////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BarLxDWmv
- 7mdmsPHdXbH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/ZrDy4Wmv721qsvIN////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wFkr/MNYbH3WV+x
- +tFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/X7H61WGx
- +F9kr/MN////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AWiw8AlhsfdPXrH7yVyy
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XrH7zWCx91NnsPAL////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8Bg7HRA2aw8i9fsfqxXbH8+12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsfz9X7H6tWaw8jODsdED////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BZrDyD2Ox9XVdsfztXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfzxY7H1eWax8g////8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BbrDqKV+x+bVdsv39XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f1fsfq7bbDrLf///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wGIq8oDY7H1SV+x+d1dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1+x+uFjsfZPiKzKA///
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wGArtcFZ7DxYV2y/O9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL88Wew
- 8mmAr9YH////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wF8r9wHaLDwcV6x+/Ndsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsfz1aLDxeXuu3An///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wGAr9YFaLDwcV6x+/Vdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x+/dosPF5gK/XB////wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wGIq8kDZ7DxYV6x+/Vdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbH89Wex8mmMsM4D////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BY7H1SV2y/O9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvzxY7H2Uf///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BbrDqJ2Cx+d1dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1+x+uFtsOsv////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BZrHyDV+x+rVdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/X7H6u2aw8hH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8Bg7HRA2Ox9XNdsvz9XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f1jsfV7g7HRA///
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AWew8i1dsfzvXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH88WWw
- 8zX///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AWew8AlfsfmvXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9fsfq3Z7DwC////wH///8B////Af///wH///8B////Af///wH///8B////Af///wFhsfdNXbH8+12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbH8/WCx+Ff///8B////Af///wH///8B////Af///wH///8B////Af///wFkrvILXrH7x12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9esfvNZK/0D////wH///8B////Af///wH///8B////Af///wH///8BYbH3V12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/2Gx+GH///8B////Af///wH///8B////Af///wH///8BbLPwC1+x
- +tFdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9esfvVabLyEf///wH///8B////Af///wH///8B////AWqv
- 7mVdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/2iv72////8B////Af///wH///8B////AYKt
- 0wlnsPHdXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9msPLhfq3YEf///wH///8B////Af//
- /wGFrtBZXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1qt9v9arfb/Wq32/1qt9v9arfb/Wq32/1qt9v9arfb/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/4Gu1WP///8B////Af//
- /wGZqbYDbK/ro12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9rr+yrmam2Bf//
- /wH///8BeqrUB2iw8e9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Z7Dy8Xet
- 3A////8B////AYCt0hVdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f91r98f////Af///wFssew7XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/arHuQ////wH///8BXbH9a12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12x/XX///8B////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv2N////Af///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL8k////wH///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/J1dtPwD////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csvypW7L8A////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8tVyx/AX///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/cNdsf0F////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfzRXbH8B////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH84V2x/An///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/O9csvwJ////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv37XbL9C///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x
- /Qv///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9fsv0L////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/W7P9Df///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yv/Q3///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9es/0P////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbX9D////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw/RH///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvoT////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbP9E////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/161/RX///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csP4V////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbT9F////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+xn///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9esf4Z////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P9brvf/WKnx/1al
- 6v9UoOT/T5fW/woQFv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8HCw7/TpbW/1Og5P9Wper/WKnx/1qu
- 9/9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbT+G///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPv/WKnw/1Og4/9Mkc7/P3ms/zJgiP8mSGb/HjhP/xYp
- Of8OGiT/BgoO/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8GCg3/Dhkj/xYo
- OP8eN07/Jkdl/zJfhv8/eKr/S5DN/1Of4/9YqfD/XLD7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x
- /Bv///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfz/Wqz1/1Gc3v8/eKv/JUdk/xcqO/8KERj/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8JEBb/Fik6/yVFYv8+dqj/UZzd/1qs9P9csfz/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9cs/wd////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8/1io8P9Mkc//NGKM/xw0Sf8KERj/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wkQFv8bMkf/M2CJ/0uQ
- zf9XqO//XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbP+Hf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9ZqvL/S4/M/y9agP8WKTr/BQgL/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8FCAr/Fig4/y5Yff9Kjsn/WKnx/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yw/B////8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH7/1Gb
- 3f83aZX/GC1A/wYJDP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/BQgL/xcrPf81ZpD/UJrb/1yx+/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csf4f////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9br/n/S4/M/ydL
- a/8MFh7/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wsUHP8mSGb/So7J/1uv+f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL7If///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+/9MkM7/JUVi/wgO
- E/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wcNEf8jQl7/S4/L/1yw
- +/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx+yH///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/1CZ2v8qT3H/ChEX/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DBQb/CA0T/w0XIf8SIS//BAYH/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wQEBf8TIi//DRgh/wgOE/8EBQb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wkP
- Ff8oTGz/T5fX/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv4h////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/VqTp/zNhif8OGSL/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/BwwR/xEgLP8bM0j/Jkhn/zJgiP8/eKr/SIrE/02T0v9RnN7/VqTq/wsSGf8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8HDBD/VqXq/1Gc3v9NlNL/SIvF/z95q/8zYYr/J0lo/xw0Sf8SIC3/CA0S/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/w0XH/8xXYX/VaPn/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W7D7I////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9arfb/P3mt/xUmNv8EBQX/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BAUG/xAc
- KP8iQVv/PXSk/02U0/9Vo+f/W6/5/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9br/n/VaPo/06V
- 1P89dqf/I0Je/xAeKf8EBQb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwQF/xMjMv8+dqn/Wq31/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w+iP///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P9OldT/IkBa/wYJDP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQFB/8TJDP/KlFy/0WF
- vP9UoeX/XLD6/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yw+v9Uoeb/Roa+/ytTdf8UJjX/BAYI/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BQgL/yA8Vv9MktD/XLH8/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csvwj////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1mr8/82Z5L/DRcg/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/Dxsm/ylOb/9HicP/VqXr/1yx
- /P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/V6bs/0iKxf8qUXL/EB0p/wMDBP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/DBUd/zRjjf9YqfH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL+I////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/02U0v8dNk3/BAYI/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBf8ZMEP/PXWm/1Si5/9csfv/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/1Wj6P8+d6n/GzJH/wQF
- B/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8EBgf/GzNI/0yR
- zv9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/iP///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W674/zpwn/8MFh//AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwME/xsyR/9Fg7v/Wavz/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1mr
- 8/9GhsD/HDVL/wMDBP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8MFRz/OGyZ/1qt9/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csf4l////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Vqbs/yZJaP8FBwr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/FCY1/0B7r/9Zq/P/XLH8/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1qs9f9Cf7T/FSg4/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wUHCf8kRWL/VaPo/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W7L+Jf//
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/TpbW/xYqPP8DBAT/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8MFR3/NmiV/1eo7v9csfz/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLH8/1ip8P84bJr/DBYf/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwQE/xUnN/9Nk9H/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /iX///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/Roa+/w0YIf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wUHCv8nSmn/Up7h/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/1Sh5P8pTm7/BQgK/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/DBYf/0OBuP9csfz/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsP4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfv/P3ms/wgNEv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/xQlNP9Ghr//W6/5/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD6/0iKxP8VKDj/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8HDBH/PHSk/1yw+/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbD+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/PHKj/wUICv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/BgkM/y5XfP9YqO//XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/WKrx/zBc
- g/8GCg3/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wUHCv85bZv/XLD7/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1ux/if///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/PXWm/wQGCP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/ER8r/0eIwv9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csfz/SYzH/xIiL/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BAUH/zpv
- nv9csfv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9bsv4n////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/Q4G3/wQHCf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DBAX/I0Je/1al6v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9Xp+3/JUdl/wQFBv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8EBgj/QHuv/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLL8J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/S5DN/wgNEv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8HDBD/NGSP/1uu+P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1uv+f83aZb/CA0R/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wcMEf9IisT/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y+yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/UZvc/w0XIP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8LFBv/QX2y/12x/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH8/0SBuP8MFh//AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CxQb/0+X1/9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/VqXq/xQkM/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8PGyX/SYzH/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/S4/M/xAeKv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8RHyz/VaPo/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Wqz1/x46Uv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8QHSn/TJLP/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9NldT/ESEu/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/xs0Sf9ZrPT/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD6/y1We/8DBAX/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8OGSP/S5DN/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/02T
- 0f8QHCj/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/K1Fz/1uw+v9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH8/z12qP8FBwr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8KEhj/RYW9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/R4nD/wwVHf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQFBv87cqL/XbH8/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/02T0f8MFRz/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8HDBD/PXWn/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8/eq3/CA4T/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/ChAX/0uQ
- zf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1eo7v8YLkH/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8FBwn/NGOM/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLH8/zZok/8FCAv/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8VKDj/V6ft/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+v8tVnr/BAUF/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DBAT/KEtr/1uv+P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9br/n/K1Fz/wQFBv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwQE/ypQcv9csPr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Eg7v/BwwR/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/GjFF/1io8P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1ip8f8dN03/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8GCg3/Qn+1/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw
- +yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9WpOr/FSc2/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/DRgi/1Gb3P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Up3f/xAdKf8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/xIhL/9Vo+j/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csPsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfv/Llh9/wMEBf8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/BQkL/0OAtf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Eg7r/BwwQ/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DBAX/K1J0/1yx+/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLD7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/So7K/woRGP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/y1Vev9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/y9b
- gf8DBAT/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgOFP9IisX/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yw+yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Wq32/x87U/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/xUoOP9ZqvL/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Zq/P/GC5B/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/HDVK/1qs9f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csPsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0F8sP8GCQz/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wYKDf9Kjsr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/0yS0P8IDRH/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wUICv8+d6n/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1ip8P8YLUD/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8uV3z/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/MV2E/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/FSc4/1eo
- 7/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f89dqf/BAcJ/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8QHir/V6ft/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1mr8/8SIS7/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQG
- CP86cJ//XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9YqfH/GC0//wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/P3mt/1yx/P9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Q4C2/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/FSc3/1io7/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/QX2y/wUH
- Cv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/GjJG/1qs9f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uv+f8cNkz/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wUHCf8+eKr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W674/x45
- Uf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwUG/0aHwP9csfz/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/So7J/wMFBv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/GzNI/1qu9/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0uR
- zv8IDhP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/x03Tv9arfb/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uv+f8fO1T/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wcMEf9JjMf/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8uWH3/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDBP9Fhb3/XLH8/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/SYvG/wMD
- BP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/K1Fz/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9WpOr/EyIw/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8YLD7/Wavz/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1qt
- 9/8aMET/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/xAeKf9Uouf/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvsn////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/Q4G3/wQFBv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/Om+d/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csfz/PXWn/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DBQb/QHqu/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL7J///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8/yRFYv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CxQc/1Wi5/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1en7v8MFh//AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/yE+WP9csfv/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- +yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1Of4/8PGyb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/ydKaf9csPr/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfv/KlBy/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8OGCH/UZze/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsvsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9Cf7T/AwME/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBP9HiMH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0qOyv8DBAX/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwME/z94
- q/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfz/J0pq/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8TIzH/V6bt/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9YqvH/FCY1/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8kRGD/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y+yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/VqXr/xMkMv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/K1J0/1yx
- /P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/y5Yff8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/ESAs/1Wj5/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsvsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/0uQzf8FCAv/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwQF/0eH
- wP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Kjcn/AwQF/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wUHCv9IisT/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/W7L+J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f83aJX/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/w8c
- KP9Vo+f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6bt/xEfLP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/M2KL/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1uy/if///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPr/IT9Z/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8iQFv/W6/6/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+v8lRmT/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/x45UP9csPr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9bsv4n////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/VqXq/xMjMP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/OGya/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/PHOj/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8RHyv/VKLm/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W7L+J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0+X1/8GCw//AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/BQcK/0ySz/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0+Y
- 2P8FCAr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgoN/0yRz/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uy/if///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9CfbL/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/xEeKv9Vo+f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Wpuz/EiIv/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8+d6n/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9bsv4n////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/MV2E/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8dN07/W674/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/W6/5/yA9Vv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/LVZ6/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD+Jf///wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH7/yJBXP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/LFV4/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8wW4H/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/x86Uv9csPv/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/iX///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1mq8v8YLUD/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/zxzpP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/QHqt/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8WKTn/WKjv/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsP4l////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Vo+j/EB0o/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBf9Jjcj/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/02T0f8DBAX/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/Dhok/1Of
- 4v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbD+Jf//
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/UZze/wgO
- E/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8JDxX/UJnZ/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9SnuD/ChEY/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wcN
- Ef9Pl9f/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w
- /iX///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/06V
- 1P8DBAT/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/EB0o/1Sh5f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/VqTq/xEgLf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DBAT/So/L/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsP4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Hh8D/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/xYoOP9XqO//XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1iq8f8YLT//AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/0OAt/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbD+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/QHqu/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8aMUX/Wq33/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9brvj/HTdN/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/89dKX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12w/iX///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/ztxoP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/HjhP/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/yE/Wf8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/N2qW/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsP4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f83aZX/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/yE/Wv9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8lRmT/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/zNijP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbD+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/NWWP/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8kRWL/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/J0xs/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8xXoX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/iX///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/zRjjP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/JUdl/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/ylO
- b/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/MFyD/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsP4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Y43/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/yVH
- Zf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8pTm//AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/zBcg/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbD+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/NGSO/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8kRWP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/KExs/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8xXoX/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/iX///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/zZolP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/IkBc/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/yVHZf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/M2KL/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsP4l////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f86cJ7/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/x45Uf9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx/P8iQFr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/zdplf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbD+Jf///wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/P3mt/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8bMkb/W674/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9br/n/HjhP/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/88cqP/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/iX///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0aGvv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/Fik5/1ip8P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/Wary/xkuQP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/Qn+0/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsP4l////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9NlNL/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/xAeKv9Uoub/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1al6/8SIS//AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/0qO
- yf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbD+Jf//
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/UZze/wcM
- Ef8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8KERj/UJrb/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9TnuL/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wcL
- D/9Oltb/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w
- /iX///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1Si
- 5v8PGyb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwUG/0uPy/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/TpXU/wQFBv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8NGCL/Up7h/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsP4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9YqfH/Fys9/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8+d6j/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0J9sv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/FSc3/1en7v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbD+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLD7/yE+WP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/Llh9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8yX4f/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/x44T/9csPr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12w/iX///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8vWX//AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/x86Uv9br/n/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPr/IkBb/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8rU3X/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsP4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/P3mt/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8SIS7/VaTp/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6fu/xQlNP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/PHOj/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbD+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/06V1P8FCQv/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgkM/02U
- 0/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1Ca3P8GCg3/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/BQgK/0uPy/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/iX///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Vo+j/ER8s/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/87caH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8/eKr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/w8cJ/9ToOP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsP4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W6/5/x87U/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/JEVi/1yw+/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPv/J0tr/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8cNUv/W6/4/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbD+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f80Y43/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/xIgLf9WpOr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6jv/xMk
- Mv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/MFyD/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12w/iX///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/SYzH/wQGCP8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8EBQf/SYvG/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0yS
- 0P8EBgf/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BAYI/0aGvv9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csP4l////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1Wj6P8RICz/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/y5Yff9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx
- /P8xX4b/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/w8cJ/9ToOP/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W7L+J////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPv/JERh/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8VKDj/WKjv/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9Zq/P/Fys9/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8hPlj/XLD7/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uy/if///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/z94
- q/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BAYH/0mMyP9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/TZPR/wQGCP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/O3Gh/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9bsv4n////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9RnN7/DRcg/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8qUXP/XLD7/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH7/y5XfP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CxQc/0+Y2P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W7L+J///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/W6/5/yE+WP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/Dhok/1ak6v9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1ip8P8PHSj/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/x44T/9br/n/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uy
- /if///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8/eKv/AwQF/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8+d6n/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9BfbL/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBP87cqL/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9bsv4n////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/U6Dk/xAdKP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/HDRJ/1qs
- 9f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9brvj/HjhP/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8OGSL/Up3g/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/W7L+J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P8pTm//AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQF
- B/9JjMj/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/TZPR/wQGB/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/Jkhm/1yx
- /P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y+yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/SIrE/wYKDv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/IkBb/1uv+P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLD7/yRFYv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgkM/0WE
- vP9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsvsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1qs9f8ZMET/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wQGCP9LkM3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/06X1v8EBwn/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/xYq
- O/9Zq/T/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/PXWm/wMEBf8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/HztT/1uv+P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx+/8iQFr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wME
- Bf86bp3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y+yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1am7P8TJDL/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDBP9FhLz/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Ii8b/AwME/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8QHiv/VqTq/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/OGuY/wME
- Bf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/FCU0/1qs9P9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9br/n/Fig5/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DBAT/NWWP/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1al
- 6/8TIzH/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/80Y43/XLH8/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/N2mW/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/EB4q/1Wj6P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx+yf///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/OnCg/wQGCP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/0+Z2f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/UZze/wkQFv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/BAUH/zdql/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1mq8v8ZLkH/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8aMUb/W674/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W674/x03T/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/xYoOf9YqfD/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/RIO6/wcMEP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/zRj
- jf9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/zZolP8DBAX/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wYKDf9CfrP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+v8mSGf/AwME/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8HCw//SYzH/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0qPy/8JDxT/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8jQl7/XLD6/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Up3f/w8cJv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/xEgLf9Vouf/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1Wk6f8UJTX/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8NFyD/UZrc/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f88dKX/BQgL/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/ID1W/1qs9f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1qs9f8jQ1//AwME/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8FBwn/Om+e/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw
- +yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W674/yREYf8DAwT/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQEBf8vWoD/XLD6/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+v8yX4f/BAYH/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/IT5Y/1uu9/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csPsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9ToOP/ESAt/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgkM/ztxof9csfz/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P89dqf/BwsP/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/Dxsm/1Ke4P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLD7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0WD
- u/8IDhP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8KERf/RIK5/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Ghr7/CxQb/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/BwsO/0OAtv9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yw+yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9csfz/M2GK/wQFB/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/w4ZI/9Lj8v/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9MktD/EB0o/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwQE/zBcg/9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csPsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1qt9v8jQV3/AwME/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/EyMx/0+Y
- 2P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Qmtz/FSc3/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/yA8Vf9arPX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/VaTp/xUoOf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8WKTr/UJna/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9RnN7/GC1A/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/xMjMf9Vo+j/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Pl9f/DRgh/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/xUnN/9NldP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Pl9f/Fys9/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wsTG/9NldP/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/0eIwf8IDhP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/ER8s/0eIwv9dsfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/P9JjMf/EyIw/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wcMEP9Eg7r/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfz/P3ir/wUICv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8MFR3/PHOj/1uv+f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1uv+v8+d6n/DRcg/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wUHCv88c6P/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx+/82aJP/AwQF/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wYKDv8sVHf/V6jv/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1ip8f8uWH3/BwsP/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBP8zYoz/XLD6/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/W6/4/y9a
- gP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BAUG/xkwRP9MktD/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/06V1P8bM0j/BAUG/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8sVXj/Wq32/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD7J////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9arfb/Lld7/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CxMb/zZo
- lP9arfX/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/Wq73/zhsmv8MFR3/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8rUnT/Wav0/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+yf///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1qt9v8xXYX/AwUG/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8EBgf/HDRK/02T0f9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/TpbW/x04Tv8EBgf/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBv8uWH3/Wqz1/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPsn////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/W6/4/zhtmv8GCg3/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDhT/MFuB/1ip8P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Zq/P/Ml+H/wkPFf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wYJDP82Z5P/W673/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH7J///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfv/RIK5/wwUHP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBP8QHyv/QHqu/1yw+v9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+/9CfrP/EiEu/wMEBP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wsSGv9BfrL/XLD7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- +yf///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/P9Qmdn/Fys9/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBf8aMkb/So/L/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLH8/0yS0P8cNEr/AwQF/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/xUoOP9OltT/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsvsn////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH8/1mq8v8rU3X/BQcJ/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBf8iQFv/T5fX/1yx
- +/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csfv/UJrb/yREYP8DBAX/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/BAYI/ylObv9YqfD/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLL9J////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH7/0OA
- tv8PGyb/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMF
- Bv8hPlf/R4nC/1uu9/9csfz/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8/1uu+P9Ii8X/IkFc/wQGCP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/Dhkj/0F8sP9csPv/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1ux/if///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/VaPn/yZIZv8FCAv/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8TIzL/M2KL/1Gc3v9arvf/XLH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx
- /P9brvf/Up3g/zRkjv8UJjX/AwQE/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8FCAr/JERh/1Sg5P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsP4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9csPv/Q4C2/xMjMf8DBAX/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8EBgn/GjBE/zVlj/9PmNj/Wavz/1yx/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfz/Wav0/1CZ
- 2v82Z5L/GzJH/wUHCv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMEBP8RIC3/QX2x/1yw+v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbD+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Xp+7/MFuC/woSGP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BAUH/xUmNv8sVHf/R4jB/1ak
- 6v9Zq/P/XLD7/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csPv/Wavz/1al6v9IisT/LVV5/xUo
- OP8EBgj/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wkQFv8uWH3/Vqbs/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/iX///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9OltX/IkFc/wYLDv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8JERf/Fys9/yVFY/8wXYT/PHSl/0mMxv9SneD/VaPn/1en7f9Zq/P/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgMEP9Zq/T/V6fu/1Wj6P9SnuD/SY3I/z11pv8xXYX/JUZk/xgtP/8KERj/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/BgoN/yA9V/9Nk9L/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9bsv4l////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+/9FhLz/GjBE/wUI
- Cv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BAUH/woSGv8SIS7/GS9C/wUHCf8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8EBQf/GS9D/xIhL/8LExr/BAYH/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8FBwn/GC1A/0OBuP9csPr/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH+Jf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1qt
- 9v8/d6r/Fig5/wQGCP8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wQG
- B/8UJjX/PXWm/1qs9f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/iP///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1mq8v89dab/GC0//wYKDf8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BgkM/xcq
- O/88cqL/WKnx/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv4j////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1qt9v9Fhb3/JUdl/w0YIf8DBAX/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMEBf8NFx//JERg/0SD
- uv9arfb/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLL8I////wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Tn+L/PHOk/x46Uv8NFx//AwQF/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DBAX/DBYe/x44T/87caH/Up3f/1yx
- /P9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx+iP///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9csfv/UZvd/z52
- qP8kQ2D/ER4q/wUIC/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/BQgK/xAdKf8jQl3/PXWm/1Ca2/9csPv/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9bsPsj////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH8/1Wk6f9Gh8D/Lll+/xgsP/8OGSP/BQkL/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/BQgL/w4YIv8XLD3/LVd7/0WGvv9Vouf/XLH8/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL+If//
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9arfb/Up3f/0mMx/8+d6n/MV6G/yVGY/8aMUX/FSY1/w8c
- J/8KEhj/BQcK/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8FBwn/ChEY/w8b
- Jv8UJjX/GjFE/yRFYv8xXYX/Pnan/0mLxv9RnN7/Wq31/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/16z
- /SH///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD6/1io
- 7/9ToOP/TpfW/0qOyv9Egrn/CQ4T/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wYKDf9Egrj/So7K/06X
- 1v9Tn+P/WKjv/1yw+v9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsvsh////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XLH+H////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yx+x////8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9ds/0d////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XLL8Hf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1yx/Bv///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9esv4b////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XrH+Gf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw+xn///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9fsv0X////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsT
- Gv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLD+Ff///wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/161/RX///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9ds/0T////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL6E///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw
- /RH///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgNEf9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dtf0P////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8IDRH/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XrP9D////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/CA0R/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/1yv/Q3///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/CxMa/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wgN
- Ef9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9bs/0N////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/wsTGv8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8IDRH/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/X7L9C////wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f8LExr/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/CA0R/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/Qv///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/1uu+P9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/CQ4T/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wYKDf9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+
- s/9CfrP/Qn6z/0J+s/9CfrP/Qn6z/0J+s/9CfrP/Wqz1/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/ftdsv0L////AV2y/YNdsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Xpuz/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/1Of4/9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvzvXLL8Cf///wFdsv2DXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6bs/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/9Tn+P/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH84V2x/An///8BXbL9g12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1em7P8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/U5/j/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/NFdsfwH////AV2y/YNdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Xpuz/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/1Of4/9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsf3DXbH9Bf///wFdsv2DXbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6bs/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/9Tn+P/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XLH9tVyx/QX///8BXbL9g12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1em7P8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/U5/j/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yy/KlbsvwD////AV2y
- /YNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9Xpuz/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/1Of
- 4/9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsvydXbT8A///
- /wFdsv2DXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/V6bs/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMDA/8DAwP/AwMD/wMD
- A/9Tn+P/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL8k///
- /wH///8BXbL9g12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1yw
- +v9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ2f9Qmdn/UJnZ/1CZ
- 2f9Qmdn/W6/5/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /Y3///8B////AV2x/Wtdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsf11////Af///wFssew7XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/arHuQ////wH///8BgK3SFV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/3Wv3x////8B////AXqq1AdosPHvXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/2ew8vF3rdwP////Af///wGZqbYDbK/ro12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9rr+yrmam2Bf///wH///8B////AYWu0Fldsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/ga7VY////wH///8B////Af///wGCrdMJZ7Dx3V2y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/ZrDy4X6t2BH///8B////Af///wH///8B////AWqv7mVdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/2iv72////8B////Af///wH///8B////Af///wFss/ALX7H60V2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/16x+9VpsvIR////Af///wH///8B////Af///wH///8B////AWGx
- 91ddsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9hsfhh////Af///wH///8B////Af///wH///8B////Af//
- /wFksPILXrL7xV2y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9esfvLZK/0D////wH///8B////Af///wH///8B////Af//
- /wH///8B////AWGx+Etdsfz7XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfz7YLH4Vf///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wFmsPQHX7H6q12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/X7H6tWev8Qv///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////AWaw8yldsfzrXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH872Wx8zP///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wGEqdADYrH2aV2y/P1dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/WOx9nmHr88D////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////AWSx8wtfsfqtXbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1+x+rllsfQP////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8BbLDsIV+x+tVdsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/1+x+t9tsOwr////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wFisfZBXbH8612y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/PFjsfZN////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8Bi67FA2Sw
- 9FddsfzxXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/PVmsfNniqzIA////wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wGBr9kFZrDyZ12x/PNdsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/16x+/dosPF5ga/ZB////wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////AXuv3gVnsfFrXbH8812y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x+/VosfB7fK/cCf///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8Bga3WBWaw8l1dsvzvXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/PNosPBtga/XB////wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wGMsM0DZLH0S2Cx+d9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/2Cx+edmsPRVjKzJA////wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wFvr+gvYLH4vV2y/P9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL8/WCx+b9vr+gz////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AW2w7RFmsfOHXbH89V2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbH872Sx9XtpsO4R////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8Bhq7RBWmw
- 7j9hsfjFXbH8/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsfz7XrL7rWSw9C2HrdED////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8BcLDqD2aw8mlgsfjhXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12x/f9esfzFYLH6R2Ww9An///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8Bca/oFWaw8nVgsfnhXbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbH9/16x+8lgsflTYrD4C////wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8BbLDpEWiw8GFjsfW/XbH8/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/YbH4t2Sx9UtjsPcL////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8Bdq/fB3av4SNksfWFY7H1xV2y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/2Ww8+dmsPKRdK/kKXOv5Af///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////AXSw
- 5AV5rt8Za6/sXWCx+JNksfW3XrL7112x/fFdsf3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y
- /f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv3/XbL9/12y/f9dsv37XbL8712y/d9dsvzPXrH8vWKx
- 96tisfaXb7Doh4at0D19rdgL////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8BeK/fA2Gy+QVdsf0FXq/4B2Cv8Aditv0JXLH9CV2x/gtcsvkNXrP7D1yw
- +hFdsv0TXbP+FVuy+xddsv4ZXLH8G1yy/B1dsv4fXLL9IVuw+yNdsfslXLH7JVyw+ydcsv4pXbL+KV2y
- /StdsvwtXbH+LVuw/C9csfwvXbP9MV2y/DFdsfwzXbH9M12x/DVcsvw1XLP8NVyz/Ddcsvw3XbP9N12z
- /jddsf05XLH9OVyw/TldsP05XLH9O1yx/Ttdsv07XbL9O1yx/Ttcsfw7XLH9O1yy/T1csv09XLL9PVyy
- /T1csv09XLL+PVyy/j1csv49XLL+PVyy/j1csv49XLL+PVyy/j1csv49XLL+PVyy/j1csv49XLL9PVyy
- /T1csv09XLL9PVyy/T1csf09XLH8O1yx/Dtcsfw7XLH9O12y/Ttdsv07XbH9O1yx/Ttcsf07XLH9O1yw
- /DtdsP05XbD9OVyw/Tlcsf05XLH9OV2x/Tldsf05XbP+N12z/jddsvw3XLL8N1yy/Ddcsvw3XbP9N12z
- /jVcs/01XLL8NVyy/DVdsvw1XbH8NV2x/DNdsfwzXbH+M12x/jNdsfwzXbH8M1yx/DNcsfwzXbL8M12y
- /DNds/4xXbP+MV2y/DFdsvwxXLH8MVyx/C9csfwvW7D8L1yw/S9dsf4vXbL+LV2y/i1csvwtXbL8LV2x
- /C1csfwtXLD8K16y/Stes/4rXbL+K12y/ildsf4pXLH+KV2z/SlesvspXLH7J12w+ydbsvsnXLL7J12x
- +yVcsvslXLL7JV6x+yVcsPsjXLH7I1uw+yNcsfshW7H+IV2x/iFcsv4fXrL+H1yz/R9csfodWrD7HV2y
- /h1csvobXbH9G1yx/RlbsfsZXrP+GV2y/hddsfsXXrP+FVyz/hVdr/4TXrH+E121/hFbsP4RXbP+D1+2
- /g9dsf4NXrX+DVuv/gtes/0LXbP9CV6y/Qlhtv0HWrX9B2Gx/Qddsf0FXbL9BV2y/QVdsv0FXbL8A2Gx
- +QN4ruAD////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af///wH///8B////Af//
- /wH///8B////Af///wH///8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
-</value>
- </data>
-</root> \ No newline at end of file
diff --git a/windows/WebUIWrapper/Program.cs b/windows/WebUIWrapper/Program.cs
deleted file mode 100644
index bfcdb831..00000000
--- a/windows/WebUIWrapper/Program.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using System.Runtime.InteropServices;
-using System.ComponentModel;
-
-namespace WebUIWrapper
-{
- [ComImport, GuidAttribute("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B"),
- InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IInternetSecurityManager
- {
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int SetSecuritySite([In] IntPtr pSite);
-
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int GetSecuritySite([Out] IntPtr pSite);
-
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int MapUrlToZone([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out UInt32 pdwZone, UInt32 dwFlags);
-
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int GetSecurityId([MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSecurityId, ref UInt32 pcbSecurityId, uint dwReserved);
-
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int ProcessUrlAction([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, UInt32 dwAction, out byte pPolicy, UInt32 cbPolicy, byte pContext, UInt32 cbContext, UInt32 dwFlags, UInt32 dwReserved);
-
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int QueryCustomPolicy([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, ref Guid guidKey, ref byte ppPolicy, ref UInt32 pcbPolicy, ref byte pContext, UInt32 cbContext, UInt32 dwReserved);
-
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int SetZoneMapping(UInt32 dwZone, [In, MarshalAs(UnmanagedType.LPWStr)] string lpszPattern, UInt32 dwFlags);
-
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int GetZoneMappings(UInt32 dwZone, out UCOMIEnumString ppenumString, UInt32 dwFlags);
- }
-
- static class Program
- {
- // constants from urlmon.h
- public const UInt32 URLZONE_LOCAL_MACHINE = 0;
- public const UInt32 URLZONE_INTRANET = URLZONE_LOCAL_MACHINE + 1;
- public const UInt32 URLZONE_TRUSTED = URLZONE_INTRANET + 1;
- public const UInt32 URLZONE_INTERNET = URLZONE_TRUSTED + 1;
- public const UInt32 URLZONE_UNTRUSTED = URLZONE_INTERNET + 1;
- public const UInt32 URLZONE_ESC_FLAG = 0x100;
- public const UInt32 SZM_CREATE = 0;
- public const UInt32 SZM_DELETE = 0x1;
-
- public static Guid CLSID_InternetSecurityManager = new Guid("7b8a2d94-0ac9-11d1-896c-00c04fb6bfc4");
- public static Guid IID_IInternetSecurityManager = new Guid("79eac9ee-baf9-11ce-8c82-00aa004ba90b");
-
- /// <summary>
- /// The main entry point for the application.
- /// </summary>
- [STAThread]
- static void Main()
- {
- try
- {
- Type t = Type.GetTypeFromCLSID(CLSID_InternetSecurityManager);
- object securityManager = Activator.CreateInstance(t);
- if (securityManager != null)
- {
- IInternetSecurityManager ism = (IInternetSecurityManager)securityManager;
- ism.SetZoneMapping(URLZONE_TRUSTED, "http://127.0.0.1", SZM_CREATE);
- ism.SetZoneMapping(URLZONE_INTRANET, "http://127.0.0.1", SZM_CREATE);
- ism.SetZoneMapping(URLZONE_ESC_FLAG | URLZONE_TRUSTED, "http://127.0.0.1", SZM_CREATE);
- ism.SetZoneMapping(URLZONE_ESC_FLAG | URLZONE_INTRANET, "http://127.0.0.1", SZM_CREATE);
- }
- }
- catch
- {
- // Okay to continue if adding URL to trusted zone doesn't work...
- }
-
- Application.EnableVisualStyles();
- Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new Form1());
- }
- }
-}
diff --git a/windows/WebUIWrapper/Properties/AssemblyInfo.cs b/windows/WebUIWrapper/Properties/AssemblyInfo.cs
deleted file mode 100644
index 5573fc09..00000000
--- a/windows/WebUIWrapper/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("ZeroTier One")]
-[assembly: AssemblyDescription("UI Wrapper")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("ZeroTier, Inc.")]
-[assembly: AssemblyProduct("ZeroTier One")]
-[assembly: AssemblyCopyright("Copyright ©2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("98eb6dae-d218-4a8c-9935-a0ccdca3e936")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/windows/WebUIWrapper/Properties/Settings.settings b/windows/WebUIWrapper/Properties/Settings.settings
deleted file mode 100644
index 39645652..00000000
--- a/windows/WebUIWrapper/Properties/Settings.settings
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
- <Profiles>
- <Profile Name="(Default)" />
- </Profiles>
- <Settings />
-</SettingsFile>
diff --git a/windows/WinUI/APIHandler.cs b/windows/WinUI/APIHandler.cs
new file mode 100644
index 00000000..92b83021
--- /dev/null
+++ b/windows/WinUI/APIHandler.cs
@@ -0,0 +1,208 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Net;
+using System.IO;
+using System.Windows;
+using Newtonsoft.Json;
+
+namespace WinUI
+{
+
+
+ public class APIHandler
+ {
+ private string authtoken;
+
+ private string url = null;
+
+ public APIHandler()
+ {
+ url = "http://127.0.0.1:9993";
+ }
+
+ public APIHandler(int port, string authtoken)
+ {
+ url = "http://localhost:" + port;
+ this.authtoken = authtoken;
+ }
+
+ public ZeroTierStatus GetStatus()
+ {
+ var request = WebRequest.Create(url + "/status" + "?auth=" + authtoken) as HttpWebRequest;
+ if (request != null)
+ {
+ request.Method = "GET";
+ request.ContentType = "application/json";
+ }
+
+ try
+ {
+ var httpResponse = (HttpWebResponse)request.GetResponse();
+ using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
+ {
+ var responseText = streamReader.ReadToEnd();
+
+ ZeroTierStatus status = null;
+ try
+ {
+ status = JsonConvert.DeserializeObject<ZeroTierStatus>(responseText);
+ }
+ catch (JsonReaderException e)
+ {
+ Console.WriteLine(e.ToString());
+ }
+ return status;
+ }
+ }
+ catch (System.Net.Sockets.SocketException)
+ {
+ return null;
+ }
+ catch (System.Net.WebException)
+ {
+ return null;
+ }
+ }
+
+ public List<ZeroTierNetwork> GetNetworks()
+ {
+ var request = WebRequest.Create(url + "/network" + "?auth=" + authtoken) as HttpWebRequest;
+ if (request == null)
+ {
+ return null;
+ }
+
+ request.Method = "GET";
+ request.ContentType = "application/json";
+
+ try
+ {
+ var httpResponse = (HttpWebResponse)request.GetResponse();
+ using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
+ {
+ var responseText = streamReader.ReadToEnd();
+
+ List<ZeroTierNetwork> networkList = null;
+ try
+ {
+ networkList = JsonConvert.DeserializeObject<List<ZeroTierNetwork>>(responseText);
+ }
+ catch (JsonReaderException e)
+ {
+ Console.WriteLine(e.ToString());
+ }
+ return networkList;
+ }
+ }
+ catch (System.Net.Sockets.SocketException)
+ {
+ return null;
+ }
+ catch (System.Net.WebException)
+ {
+ return null;
+ }
+ }
+
+ public void JoinNetwork(string nwid)
+ {
+ var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest;
+ if (request == null)
+ {
+ return;
+ }
+
+ request.Method = "POST";
+
+ try
+ {
+ var httpResponse = (HttpWebResponse)request.GetResponse();
+
+ if (httpResponse.StatusCode != HttpStatusCode.OK)
+ {
+ Console.WriteLine("Error sending join network message");
+ }
+ }
+ catch (System.Net.Sockets.SocketException)
+ {
+ MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service.");
+ }
+ catch (System.Net.WebException)
+ {
+ MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service.");
+ }
+ }
+
+ public void LeaveNetwork(string nwid)
+ {
+ var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest;
+ if (request == null)
+ {
+ return;
+ }
+
+ request.Method = "DELETE";
+
+ try
+ {
+ var httpResponse = (HttpWebResponse)request.GetResponse();
+
+ if (httpResponse.StatusCode != HttpStatusCode.OK)
+ {
+ Console.WriteLine("Error sending leave network message");
+ }
+ }
+ catch (System.Net.Sockets.SocketException)
+ {
+ MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service.");
+ }
+ catch (System.Net.WebException)
+ {
+ MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service.");
+ }
+ }
+
+ public List<ZeroTierPeer> GetPeers()
+ {
+ var request = WebRequest.Create(url + "/peer" + "?auth=" + authtoken) as HttpWebRequest;
+ if (request == null)
+ {
+ return null;
+ }
+
+ request.Method = "GET";
+ request.ContentType = "application/json";
+
+ try
+ {
+ var httpResponse = (HttpWebResponse)request.GetResponse();
+ using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
+ {
+ var responseText = streamReader.ReadToEnd();
+ //Console.WriteLine(responseText);
+ List<ZeroTierPeer> peerList = null;
+ try
+ {
+ peerList = JsonConvert.DeserializeObject<List<ZeroTierPeer>>(responseText);
+ }
+ catch (JsonReaderException e)
+ {
+ Console.WriteLine(e.ToString());
+ }
+ return peerList;
+ }
+ }
+ catch (System.Net.Sockets.SocketException)
+ {
+ return null;
+ }
+ catch (System.Net.WebException)
+ {
+ return null;
+ }
+ }
+ }
+}
diff --git a/windows/WebUIWrapper/App.config b/windows/WinUI/App.config
index 8e156463..8e156463 100644
--- a/windows/WebUIWrapper/App.config
+++ b/windows/WinUI/App.config
diff --git a/windows/WinUI/App.xaml b/windows/WinUI/App.xaml
new file mode 100644
index 00000000..08b9b792
--- /dev/null
+++ b/windows/WinUI/App.xaml
@@ -0,0 +1,14 @@
+<Application x:Class="WinUI.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ StartupUri="MainWindow.xaml">
+ <Application.Resources>
+
+ <ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
+ <ResourceDictionary Source="Simple Styles.xaml"/>
+ </ResourceDictionary.MergedDictionaries>
+ </ResourceDictionary>
+
+ </Application.Resources>
+</Application>
diff --git a/windows/WinUI/App.xaml.cs b/windows/WinUI/App.xaml.cs
new file mode 100644
index 00000000..a97edde7
--- /dev/null
+++ b/windows/WinUI/App.xaml.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace WinUI
+{
+ /// <summary>
+ /// Interaction logic for App.xaml
+ /// </summary>
+ public partial class App : Application
+ {
+ }
+}
diff --git a/windows/WinUI/Fonts/segoeui.ttf b/windows/WinUI/Fonts/segoeui.ttf
new file mode 100644
index 00000000..fc18ebd0
--- /dev/null
+++ b/windows/WinUI/Fonts/segoeui.ttf
Binary files differ
diff --git a/windows/WinUI/Fonts/segoeuib.ttf b/windows/WinUI/Fonts/segoeuib.ttf
new file mode 100644
index 00000000..5f31e0ca
--- /dev/null
+++ b/windows/WinUI/Fonts/segoeuib.ttf
Binary files differ
diff --git a/windows/WinUI/Fonts/segoeuii.ttf b/windows/WinUI/Fonts/segoeuii.ttf
new file mode 100644
index 00000000..7efb70d6
--- /dev/null
+++ b/windows/WinUI/Fonts/segoeuii.ttf
Binary files differ
diff --git a/windows/WinUI/Fonts/segoeuiz.ttf b/windows/WinUI/Fonts/segoeuiz.ttf
new file mode 100644
index 00000000..d7bb186b
--- /dev/null
+++ b/windows/WinUI/Fonts/segoeuiz.ttf
Binary files differ
diff --git a/windows/WinUI/MainWindow.xaml b/windows/WinUI/MainWindow.xaml
new file mode 100644
index 00000000..d71a90df
--- /dev/null
+++ b/windows/WinUI/MainWindow.xaml
@@ -0,0 +1,132 @@
+<Window
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:local="clr-namespace:WinUI"
+ mc:Ignorable="d" x:Class="WinUI.MainWindow"
+ Title="ZeroTier One" Height="500" Width="425" Icon="ZeroTierIcon.ico">
+
+ <Window.Resources>
+ <SolidColorBrush x:Key="GreenBrush" Color="#ff91a2a3"/>
+
+ <SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
+
+ <SolidColorBrush x:Key="GreenDisabledBrush" Color="#FF234447" />
+
+ <SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
+
+ <SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
+
+ <SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
+
+ <Style TargetType="{x:Type DataGrid}">
+ <Setter Property="Background" Value="#FFF" />
+ <Setter Property="AlternationCount" Value="2" />
+ </Style>
+
+ <Style TargetType="{x:Type DataGridRow}">
+ <Style.Triggers>
+ <Trigger Property="ItemsControl.AlternationIndex" Value="0">
+ <Setter Property="Background" Value="#EEE"></Setter>
+ </Trigger>
+ <Trigger Property="ItemsControl.AlternationIndex" Value="1">
+ <Setter Property="Background" Value="#FFF"></Setter>
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+
+ <Style TargetType="{x:Type TabItem}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type TabItem}">
+ <Grid>
+ <Border
+ Name="Border"
+ Margin="0,0,-4,0"
+ Background="{StaticResource GreenBrush}"
+ BorderBrush="{StaticResource SolidBorderBrush}"
+ BorderThickness="1,1,1,1"
+ CornerRadius="2,12,0,0" >
+ <ContentPresenter x:Name="ContentSite"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ ContentSource="Header"
+ Margin="12,2,12,2"
+ RecognizesAccessKey="True"/>
+ </Border>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Panel.ZIndex" Value="100" />
+ <Setter TargetName="Border" Property="Background" Value="{StaticResource GreenDisabledBrush}" />
+ <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
+ <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
+ <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" />
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </Window.Resources>
+
+ <DockPanel>
+ <StatusBar DockPanel.Dock="Bottom" Height="26" Background="#FF234447" Margin="0">
+ <StatusBar.ItemsPanel>
+ <ItemsPanelTemplate>
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition Width="*"/>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition Width="Auto"/>
+ </Grid.ColumnDefinitions>
+ </Grid>
+ </ItemsPanelTemplate>
+ </StatusBar.ItemsPanel>
+ <StatusBarItem Grid.Column="0" x:Name="networkId" Content="deadbeef00" Foreground="White" FontFamily="Lucida Console"/>
+ <StatusBarItem Grid.Column="1" x:Name="onlineStatus" Content="ONLINE" Foreground="White" FontFamily="Lucida Console"/>
+ <StatusBarItem Grid.Column="2" x:Name="versionString" Content="1.0.5" Foreground="White" FontFamily="Lucida Console"/>
+ <StatusBarItem Grid.Column="3" x:Name="blank" Content="" Height="43" Foreground="White"/>
+ <StatusBarItem Grid.Column="4">
+ <TextBox x:Name="joinNetworkID" TextWrapping="Wrap" Width="140" HorizontalAlignment="Right" ToolTip="Enter Network ID" PreviewTextInput="OnNetworkEntered" MaxLength="16" FontFamily="Lucida Console" FontSize="12" BorderThickness="1"/>
+ </StatusBarItem>
+ <StatusBarItem Grid.Column="5" x:Name="statusBarButton" Foreground="White" RenderTransformOrigin="0.789,0.442">
+ <Button x:Name="joinButton" Content="Join" Background="#FFFFB354" Width="76" Click="joinButton_Click"/>
+ </StatusBarItem>
+ </StatusBar>
+ <!--<TabControl Margin="0,0,0,0">
+ <TabItem x:Name="Networks" Header="Networks" Foreground="White" IsSelected="True" IsManipulationEnabled="True">-->
+ <Grid Background="LightGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+ <local:NetworksPage x:Name="networksPage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0" Margin="0,0,0,0"/>
+ </Grid>
+ <!--</TabItem>-->
+ <!--<TabItem x:Name="Peers" Header="Peers" Foreground="White">
+ <Grid Background="#FFE5E5E5" HorizontalAlignment="Left" VerticalAlignment="Top">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+ <local:PeersPage x:Name="peersPage" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="0" Grid.Row="0"/>
+ </Grid>
+ </TabItem>-->
+ <!--</TabControl>-->
+ </DockPanel>
+</Window>
diff --git a/windows/WinUI/MainWindow.xaml.cs b/windows/WinUI/MainWindow.xaml.cs
new file mode 100644
index 00000000..47f00bfe
--- /dev/null
+++ b/windows/WinUI/MainWindow.xaml.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Timers;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+
+namespace WinUI
+{
+ /// <summary>
+ /// Interaction logic for MainWindow.xaml
+ /// </summary>
+ public partial class MainWindow : Window
+ {
+ APIHandler handler;
+ Regex charRegex = new Regex("[0-9a-fxA-FX]");
+ Regex wholeStringRegex = new Regex("^[0-9a-fxA-FX]+$");
+
+ Timer timer = new Timer();
+
+ bool connected = false;
+
+ public MainWindow()
+ {
+ InitializeComponent();
+
+ if (InitAPIHandler())
+ {
+ networksPage.SetAPIHandler(handler);
+
+ updateStatus();
+ if (!connected)
+ {
+ MessageBox.Show("Unable to connect to ZeroTier Service.");
+ }
+
+ updateNetworks();
+ //updatePeers();
+
+ DataObject.AddPastingHandler(joinNetworkID, OnPaste);
+
+ timer.Elapsed += new ElapsedEventHandler(OnUpdateTimer);
+ timer.Interval = 2000;
+ timer.Enabled = true;
+ }
+ }
+
+ private bool InitAPIHandler()
+ {
+ String ztDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\ZeroTier\\One";
+ String authToken = "";
+ Int32 port = 9993;
+ try
+ {
+ byte[] tmp = File.ReadAllBytes(ztDir + "\\authtoken.secret");
+ authToken = System.Text.Encoding.ASCII.GetString(tmp).Trim();
+ }
+ catch
+ {
+ MessageBox.Show("Unable to read ZeroTier One authtoken.secret from:\r\n" + ztDir, "ZeroTier One");
+ this.Close();
+ return false;
+ }
+
+ if ((authToken == null) || (authToken.Length <= 0))
+ {
+ MessageBox.Show("Unable to read ZeroTier One authtoken.secret from:\r\n" + ztDir, "ZeroTier One");
+ this.Close();
+ return false;
+ }
+ try
+ {
+ byte[] tmp = File.ReadAllBytes(ztDir + "\\zerotier-one.port");
+ port = Int32.Parse(System.Text.Encoding.ASCII.GetString(tmp).Trim());
+ if ((port <= 0) || (port > 65535))
+ port = 9993;
+ }
+ catch
+ {
+ }
+
+ handler = new APIHandler(port, authToken);
+ return true;
+ }
+
+ private void updateStatus()
+ {
+ var status = handler.GetStatus();
+
+ if (status != null)
+ {
+ connected = true;
+
+ networkId.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+ {
+ this.networkId.Content = status.Address;
+ }));
+ versionString.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+ {
+ this.versionString.Content = status.Version;
+ }));
+ onlineStatus.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+ {
+ this.onlineStatus.Content = (status.Online ? "ONLINE" : "OFFLINE");
+ }));
+ }
+ else
+ {
+ connected = false;
+
+ networkId.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+ {
+ this.networkId.Content = "";
+ }));
+ versionString.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+ {
+ this.versionString.Content = "0";
+ }));
+ onlineStatus.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+ {
+ this.onlineStatus.Content = "OFFLINE";
+ }));
+ }
+ }
+
+ private void updateNetworks()
+ {
+ var networks = handler.GetNetworks();
+
+ networksPage.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+ {
+ networksPage.setNetworks(networks);
+ }));
+ }
+
+ private void updatePeers()
+ {
+ //var peers = handler.GetPeers();
+
+ //peersPage.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
+ //{
+ // peersPage.SetPeers(peers);
+ //}));
+ }
+
+ private void OnUpdateTimer(object source, ElapsedEventArgs e)
+ {
+ updateStatus();
+ updateNetworks();
+ //updatePeers();
+ }
+
+ private void joinButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (joinNetworkID.Text.Length < 16)
+ {
+ MessageBox.Show("Invalid Network ID");
+ }
+ else
+ {
+ handler.JoinNetwork(joinNetworkID.Text);
+ }
+ }
+
+ private void OnNetworkEntered(object sender, TextCompositionEventArgs e)
+ {
+ e.Handled = !charRegex.IsMatch(e.Text);
+ }
+
+ private void OnPaste(object sender, DataObjectPastingEventArgs e)
+ {
+ var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
+ if (!isText) return;
+
+ var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
+
+ if (!wholeStringRegex.IsMatch(text))
+ {
+ e.CancelCommand();
+ }
+ }
+ }
+}
diff --git a/windows/WinUI/NetworkInfoView.xaml b/windows/WinUI/NetworkInfoView.xaml
new file mode 100644
index 00000000..54ff0375
--- /dev/null
+++ b/windows/WinUI/NetworkInfoView.xaml
@@ -0,0 +1,73 @@
+<UserControl Background="LightGray" x:Class="WinUI.NetworkInfoView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ mc:Ignorable="d"
+ >
+
+ <Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1" CornerRadius="8,8,8,8">
+ <Grid Background="GhostWhite" Margin="10,10,10,10">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="auto"/>
+ <ColumnDefinition Width="10"/>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ </Grid.RowDefinitions>
+
+ <Grid Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="auto"/>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+
+ <TextBox x:Name="networkId" Text="8056c2e21c000001" HorizontalAlignment="Left" Grid.Column="0" Foreground="#FF91A2A3" FontFamily="Lucida Console" BorderThickness="0" IsReadOnly="true" Background="Transparent"/>
+ <TextBox x:Name="networkName" Text="earth.zerotier.net" HorizontalAlignment="Right" Grid.Column="1" Foreground="#FF000000" BorderThickness="0" IsReadOnly="true" Background="Transparent"/>
+ </Grid>
+
+ <Separator Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3"/>
+
+ <TextBlock TextWrapping="Wrap" Text="Status" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="2" Foreground="#FF000000"/>
+ <TextBlock TextWrapping="Wrap" Text="Type" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="3" Foreground="#FF000000"/>
+ <TextBlock TextWrapping="Wrap" Text="MAC" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="4" Foreground="#FF000000"/>
+ <TextBlock TextWrapping="Wrap" Text="MTU" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="5" Foreground="#FF000000"/>
+ <TextBlock TextWrapping="Wrap" Text="Broadcast" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="6" Foreground="#FF000000"/>
+ <TextBlock TextWrapping="Wrap" Text="Bridging" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="7" Foreground="#FF000000"/>
+ <TextBlock TextWrapping="Wrap" Text="Device" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="8" Foreground="#FF000000"/>
+ <TextBlock TextWrapping="Wrap" Text="Managed IPs" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="9" Foreground="#FF000000"/>
+
+ <Rectangle Grid.Column="2" Grid.Row="2" Grid.RowSpan="8" Fill="#FFEEEEEE"/>
+
+ <TextBlock x:Name="networkStatus" FontFamily="Lucida Console" TextWrapping="Wrap" HorizontalAlignment="Right" Text="OK" TextAlignment="Right" Grid.Column="2" Grid.Row="2" Foreground="#FF000000"/>
+ <TextBlock x:Name="networkType" FontFamily="Lucida Console" TextWrapping="Wrap" Text="PUBLIC" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="3" Foreground="#FF000000"/>
+ <TextBlock x:Name="macAddress" FontFamily="Lucida Console" TextWrapping="Wrap" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="4" Foreground="#FF000000"><Span><Run Text="02:83:4a:1e:4b:3a"/></Span></TextBlock>
+ <TextBlock x:Name="mtu" FontFamily="Lucida Console" TextWrapping="Wrap" Text="2800" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="5" Foreground="#FF000000"/>
+ <TextBlock x:Name="broadcastEnabled" FontFamily="Lucida Console" TextWrapping="Wrap" Text="ENABLED" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="6" Foreground="#FF000000"/>
+ <TextBlock x:Name="bridgingEnabled" FontFamily="Lucida Console" TextWrapping="Wrap" Text="DISABLED" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="7" Background="#FFEEEEEE" Foreground="#FF000000"/>
+ <TextBlock x:Name="deviceName" FontFamily="Lucida Console" TextWrapping="Wrap" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="8" Foreground="#FF000000"><Span><Run Text="ethernet_32771"/></Span></TextBlock>
+ <TextBlock x:Name="managedIps" TextWrapping="Wrap" FontFamily="Lucida Console" HorizontalAlignment="Right" TextAlignment="Right" Grid.Column="2" Grid.Row="9" Foreground="#FF000000"><Span><Run Text="28.2.169.248/7 "/></Span><LineBreak/><Span><Run Text="fd80:56c2:e21c:0000:0199:9383:4a02:a9f8/88"/></Span></TextBlock>
+
+ <Separator Grid.Column="0" Grid.Row="10" Grid.ColumnSpan="3"/>
+
+ <Grid Grid.Column="0" Grid.Row="11" Grid.ColumnSpan="3" Background="GhostWhite">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+ <Button x:Name="leaveButton" Content="Leave" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="75" Background="#FFFFB354" Click="leaveButton_Click"/>
+ </Grid>
+ </Grid>
+ </Border>
+</UserControl>
diff --git a/windows/WinUI/NetworkInfoView.xaml.cs b/windows/WinUI/NetworkInfoView.xaml.cs
new file mode 100644
index 00000000..ccdec288
--- /dev/null
+++ b/windows/WinUI/NetworkInfoView.xaml.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace WinUI
+{
+ /// <summary>
+ /// Interaction logic for NetworkInfoView.xaml
+ /// </summary>
+ public partial class NetworkInfoView : UserControl
+ {
+ private APIHandler handler;
+ private ZeroTierNetwork network;
+
+ public NetworkInfoView(APIHandler handler, ZeroTierNetwork network)
+ {
+ InitializeComponent();
+
+ this.handler = handler;
+ this.network = network;
+
+ UpdateNetworkData();
+ }
+
+ private void UpdateNetworkData()
+ {
+ this.networkId.Text = network.NetworkId;
+ this.networkName.Text = network.NetworkName;
+ this.networkStatus.Text = network.NetworkStatus;
+ this.networkType.Text = network.NetworkType;
+ this.macAddress.Text = network.MacAddress;
+ this.mtu.Text = network.MTU.ToString();
+ this.broadcastEnabled.Text = (network.BroadcastEnabled ? "ENABLED" : "DISABLED");
+ this.bridgingEnabled.Text = (network.Bridge ? "ENABLED" : "DISABLED");
+ this.deviceName.Text = network.DeviceName;
+
+ string iplist = "";
+ for (int i = 0; i < network.AssignedAddresses.Length; ++i)
+ {
+ iplist += network.AssignedAddresses[i];
+ if (i < (network.AssignedAddresses.Length - 1))
+ iplist += "\n";
+ }
+
+ this.managedIps.Text = iplist;
+ }
+
+ public bool HasNetwork(ZeroTierNetwork network)
+ {
+ if (this.network.NetworkId.Equals(network.NetworkId))
+ return true;
+
+ return false;
+ }
+
+ private void leaveButton_Click(object sender, RoutedEventArgs e)
+ {
+ handler.LeaveNetwork(network.NetworkId);
+ }
+ }
+}
diff --git a/windows/WinUI/NetworksPage.xaml b/windows/WinUI/NetworksPage.xaml
new file mode 100644
index 00000000..6f95bc05
--- /dev/null
+++ b/windows/WinUI/NetworksPage.xaml
@@ -0,0 +1,13 @@
+<UserControl x:Class="WinUI.NetworksPage"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ mc:Ignorable="d"
+ d:DesignHeight="300" d:DesignWidth="300">
+ <ScrollViewer x:Name="MyScrollViewer" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
+ <UniformGrid x:Name="wrapPanel" Background="#FFDDDDDD" HorizontalAlignment="Stretch" VerticalAlignment="Top" Columns="1">
+
+ </UniformGrid>
+ </ScrollViewer>
+</UserControl>
diff --git a/windows/WinUI/NetworksPage.xaml.cs b/windows/WinUI/NetworksPage.xaml.cs
new file mode 100644
index 00000000..5a0dc19d
--- /dev/null
+++ b/windows/WinUI/NetworksPage.xaml.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace WinUI
+{
+ /// <summary>
+ /// Interaction logic for NetworksPage.xaml
+ /// </summary>
+ public partial class NetworksPage : UserControl
+ {
+ private APIHandler handler;
+
+ public NetworksPage()
+ {
+ InitializeComponent();
+ }
+
+ public void SetAPIHandler(APIHandler handler)
+ {
+ this.handler = handler;
+ }
+
+ public void setNetworks(List<ZeroTierNetwork> networks)
+ {
+ this.wrapPanel.Children.Clear();
+ if (networks == null)
+ {
+ return;
+ }
+
+ for (int i = 0; i < networks.Count; ++i)
+ {
+ this.wrapPanel.Children.Add(
+ new NetworkInfoView(
+ handler,
+ networks.ElementAt<ZeroTierNetwork>(i)));
+ }
+ }
+ }
+}
diff --git a/windows/WinUI/PeersPage.xaml b/windows/WinUI/PeersPage.xaml
new file mode 100644
index 00000000..57b11edf
--- /dev/null
+++ b/windows/WinUI/PeersPage.xaml
@@ -0,0 +1,26 @@
+<UserControl x:Class="WinUI.PeersPage"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ mc:Ignorable="d"
+ d:DesignHeight="300" d:DesignWidth="300" Background="White" Foreground="Black">
+
+ <DataGrid x:Name="dataGrid" GridLinesVisibility="None" AutoGenerateColumns="False" CanUserResizeColumns="True" Margin="0,0,0,0" CanUserReorderColumns="False" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto" CanUserSortColumns="False">
+ <DataGrid.CellStyle>
+ <Style TargetType="DataGridCell">
+ <Setter Property="BorderThickness" Value="0"/>
+ <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
+ </Style>
+ </DataGrid.CellStyle>
+ <DataGrid.Columns>
+ <DataGridTextColumn Header="Address" Binding="{Binding Address}"/>
+ <DataGridTextColumn Header="Version" Binding="{Binding VersionString}"/>
+ <DataGridTextColumn Header="Latency" Binding="{Binding Latency}"/>
+ <DataGridTextColumn Header="Data Paths" Binding="{Binding DataPaths}"/>
+ <DataGridTextColumn Header="Last Unicast" Binding="{Binding LastUnicastFrame}"/>
+ <DataGridTextColumn Header="Last Multicast" Binding="{Binding LastMulticastFrame}"/>
+ <DataGridTextColumn Width="*" Header="Role" Binding="{Binding Role}"/>
+ </DataGrid.Columns>
+ </DataGrid>
+</UserControl>
diff --git a/windows/WinUI/PeersPage.xaml.cs b/windows/WinUI/PeersPage.xaml.cs
new file mode 100644
index 00000000..fac22a49
--- /dev/null
+++ b/windows/WinUI/PeersPage.xaml.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace WinUI
+{
+ /// <summary>
+ /// Interaction logic for PeersPage.xaml
+ /// </summary>
+ public partial class PeersPage : UserControl
+ {
+ private List<ZeroTierPeer> peersList = new List<ZeroTierPeer>();
+
+ public PeersPage()
+ {
+ InitializeComponent();
+
+ dataGrid.ItemsSource = peersList;
+ }
+
+ public void SetPeers(List<ZeroTierPeer> list)
+ {
+ if (list == null)
+ return;
+
+
+ foreach(ZeroTierPeer p in list)
+ {
+ ZeroTierPeer curPeer = peersList.Find(peer => peer.Equals(p));
+ if (curPeer == null)
+ {
+ peersList.Add(p);
+ }
+ else
+ {
+ curPeer.Update(p);
+ }
+ }
+
+ dataGrid.Items.Refresh();
+ }
+ }
+}
diff --git a/windows/WinUI/Properties/AssemblyInfo.cs b/windows/WinUI/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..9c7cd133
--- /dev/null
+++ b/windows/WinUI/Properties/AssemblyInfo.cs
@@ -0,0 +1,56 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ZeroTier One")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("ZeroTier, Inc")]
+[assembly: AssemblyProduct("ZeroTier One")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
+//inside a <PropertyGroup>. For example, if you are using US english
+//in your source files, set the <UICulture> to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: NeutralResourcesLanguageAttribute("en-US")]
diff --git a/windows/WebUIWrapper/Properties/Resources.Designer.cs b/windows/WinUI/Properties/Resources.Designer.cs
index 463c7ea3..57a56f7d 100644
--- a/windows/WebUIWrapper/Properties/Resources.Designer.cs
+++ b/windows/WinUI/Properties/Resources.Designer.cs
@@ -1,17 +1,17 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.34209
+// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
-namespace WebUIWrapper.Properties {
- using System;
-
-
+namespace WinUI.Properties
+{
+
+
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
@@ -22,40 +22,48 @@ namespace WebUIWrapper.Properties {
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Resources {
-
+ internal class Resources
+ {
+
private static global::System.Resources.ResourceManager resourceMan;
-
+
private static global::System.Globalization.CultureInfo resourceCulture;
-
+
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Resources() {
+ internal Resources()
+ {
}
-
+
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WebUIWrapper.Properties.Resources", typeof(Resources).Assembly);
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinUI.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
-
+
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
- get {
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
return resourceCulture;
}
- set {
+ set
+ {
resourceCulture = value;
}
}
diff --git a/windows/WebUIWrapper/Properties/Resources.resx b/windows/WinUI/Properties/Resources.resx
index af7dbebb..af7dbebb 100644
--- a/windows/WebUIWrapper/Properties/Resources.resx
+++ b/windows/WinUI/Properties/Resources.resx
diff --git a/windows/WebUIWrapper/Properties/Settings.Designer.cs b/windows/WinUI/Properties/Settings.Designer.cs
index 8115e015..6812cccd 100644
--- a/windows/WebUIWrapper/Properties/Settings.Designer.cs
+++ b/windows/WinUI/Properties/Settings.Designer.cs
@@ -1,24 +1,28 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.34209
+// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
-namespace WebUIWrapper.Properties {
-
-
+namespace WinUI.Properties
+{
+
+
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
-
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default {
- get {
+
+ public static Settings Default
+ {
+ get
+ {
return defaultInstance;
}
}
diff --git a/windows/WinUI/Properties/Settings.settings b/windows/WinUI/Properties/Settings.settings
new file mode 100644
index 00000000..033d7a5e
--- /dev/null
+++ b/windows/WinUI/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ No newline at end of file
diff --git a/windows/WinUI/Simple Styles.xaml b/windows/WinUI/Simple Styles.xaml
new file mode 100644
index 00000000..f2ddedf9
--- /dev/null
+++ b/windows/WinUI/Simple Styles.xaml
@@ -0,0 +1,1121 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/interactivedesigner/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
+
+ <!-- SimpleStyles.XAML defines a set of control styles which are simplified starting points for creating your own controls -->
+
+ <!-- Brushes : These are used to define the color for background, foreground, selection, enabled etc of all controls
+ If you want to change the color of a control you can just chnage the brush; if you want to add a new shape or change arrangement then also edit the template -->
+
+ <!-- NormalBrush is used as the Background for SimpleButton, SimpleRepeatButton -->
+ <LinearGradientBrush x:Key="NormalBrush" EndPoint="0,1" StartPoint="0,0">
+ <GradientStop Color="#EEE" Offset="0.0"/>
+ <GradientStop Color="#CCC" Offset="1.0"/>
+ </LinearGradientBrush>
+ <LinearGradientBrush x:Key="NormalBorderBrush" EndPoint="0,1" StartPoint="0,0">
+ <GradientStop Color="#CCC" Offset="0.0"/>
+ <GradientStop Color="#444" Offset="1.0"/>
+ </LinearGradientBrush>
+
+ <!-- LightBrush is used for content areas such as Menu, Tab Control background -->
+ <LinearGradientBrush x:Key="LightBrush" EndPoint="0,1" StartPoint="0,0">
+ <GradientStop Color="#FFF" Offset="0.0"/>
+ <GradientStop Color="#EEE" Offset="1.0"/>
+ </LinearGradientBrush>
+
+ <!-- MouseOverBrush is used for MouseOver in Button, Radio Button, CheckBox -->
+ <LinearGradientBrush x:Key="MouseOverBrush" EndPoint="0,1" StartPoint="0,0">
+ <GradientStop Color="#FFF" Offset="0.0"/>
+ <GradientStop Color="#AAA" Offset="1.0"/>
+ </LinearGradientBrush>
+
+ <!-- PressedBrush is used for Pressed in Button, Radio Button, CheckBox -->
+ <LinearGradientBrush x:Key="PressedBrush" EndPoint="0,1" StartPoint="0,0">
+ <GradientStop Color="#BBB" Offset="0.0"/>
+ <GradientStop Color="#EEE" Offset="0.1"/>
+ <GradientStop Color="#EEE" Offset="0.9"/>
+ <GradientStop Color="#FFF" Offset="1.0"/>
+ </LinearGradientBrush>
+ <LinearGradientBrush x:Key="PressedBorderBrush" EndPoint="0,1" StartPoint="0,0">
+ <GradientStop Color="#444" Offset="0.0"/>
+ <GradientStop Color="#888" Offset="1.0"/>
+ </LinearGradientBrush>
+
+ <!-- SelectedBackgroundBrush is used for the Selected item in ListBoxItem, ComboBoxItem-->
+ <SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD"/>
+
+ <!-- Disabled Brushes are used for the Disabled look of each control -->
+ <SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888"/>
+ <SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE"/>
+ <SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA"/>
+
+ <!-- Used for background of ScrollViewer, TreeView, ListBox, Expander, TextBox, Tab Control -->
+ <SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF"/>
+
+ <!-- DefaultedBorderBrush is used to show KeyBoardFocus -->
+ <LinearGradientBrush x:Key="DefaultedBorderBrush" EndPoint="0,1" StartPoint="0,0">
+ <GradientStop Color="#777" Offset="0.0"/>
+ <GradientStop Color="#000" Offset="1.0"/>
+ </LinearGradientBrush>
+
+ <SolidColorBrush x:Key="SolidBorderBrush" Color="#888"/>
+ <SolidColorBrush x:Key="LightBorderBrush" Color="#AAA"/>
+ <SolidColorBrush x:Key="LightColorBrush" Color="#DDD"/>
+
+ <!-- Used for Checkmark, Radio button, TreeViewItem, Expander ToggleButton glyphs -->
+ <SolidColorBrush x:Key="GlyphBrush" Color="#444"/>
+
+
+ <!-- Style and Template pairs are used to define each control Part -->
+ <!-- The Style provides default values on the control; the Template gives the elements for each control -->
+
+ <!-- SimpleButtonFocusVisual is used to show keyboard focus around a SimpleButton control -->
+ <Style x:Key="SimpleButtonFocusVisual">
+ <Setter Property="Control.Template">
+ <Setter.Value>
+ <ControlTemplate>
+ <Border>
+ <Rectangle Margin="2" Stroke="#60000000" StrokeThickness="1" StrokeDashArray="1 2"/>
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple Button - This control sets brushes on each state. Note that these brushes must be listed above since they are static resources -->
+ <Style x:Key="SimpleButton" TargetType="{x:Type Button}" BasedOn="{x:Null}">
+ <Setter Property="FocusVisualStyle" Value="{DynamicResource SimpleButtonFocusVisual}"/>
+ <Setter Property="Background" Value="{DynamicResource NormalBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Button}">
+
+ <!-- We use Grid as a root because it is easy to add more elements to customize the button -->
+ <Grid x:Name="Grid">
+ <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"/>
+
+ <!-- Content Presenter is where the text content etc is placed by the control -->
+ <!-- The bindings are useful so that the control can be parameterized without editing the template -->
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
+ </Grid>
+
+ <!--Each state sets a brush on the Border in the template -->
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsKeyboardFocused" Value="true">
+ <Setter Property="BorderBrush" Value="{DynamicResource DefaultedBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsMouseOver" Value="true">
+ <Setter Property="Background" Value="{DynamicResource MouseOverBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsPressed" Value="true">
+ <Setter Property="Background" Value="{DynamicResource PressedBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource PressedBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="true"/>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <Style x:Key="RadioButtonFocusVisual">
+ <Setter Property="Control.Template">
+ <Setter.Value>
+ <ControlTemplate>
+ <Border>
+ <Rectangle Margin="15,0,0,0" Stroke="#60000000" StrokeThickness="1" StrokeDashArray="1 2"/>
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <Style x:Key="CheckBoxFocusVisual">
+ <Setter Property="Control.Template">
+ <Setter.Value>
+ <ControlTemplate>
+ <Border>
+ <Rectangle Margin="15,0,0,0" Stroke="#60000000" StrokeThickness="1" StrokeDashArray="1 2"/>
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple CheckBox -->
+ <Style x:Key="SimpleCheckBox" TargetType="{x:Type CheckBox}">
+ <Setter Property="SnapsToDevicePixels" Value="true"/>
+ <Setter Property="FocusVisualStyle" Value="{DynamicResource CheckBoxFocusVisual}"/>
+ <Setter Property="Background" Value="{DynamicResource NormalBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type CheckBox}">
+
+ <!-- BulletDecorator is used to provide baseline alignment between the checkmark and the Content -->
+ <BulletDecorator Background="Transparent">
+ <BulletDecorator.Bullet>
+ <Grid Width="13" Height="13">
+ <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
+ <Path x:Name="CheckMark" Stroke="{DynamicResource GlyphBrush}" StrokeThickness="2" SnapsToDevicePixels="False" Data="M 0 0 L 13 13 M 0 13 L 13 0"/>
+ </Grid>
+ </BulletDecorator.Bullet>
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
+ </BulletDecorator>
+
+ <!-- This uses Visibility to hide and show the CheckMark on IsChecked -->
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsChecked" Value="false">
+ <Setter Property="Visibility" Value="Collapsed" TargetName="CheckMark"/>
+ </Trigger>
+ <Trigger Property="IsMouseOver" Value="true">
+ <Setter Property="Background" Value="{DynamicResource MouseOverBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsPressed" Value="true">
+ <Setter Property="Background" Value="{DynamicResource PressedBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource PressedBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple Radio Button -->
+ <Style x:Key="SimpleRadioButton" TargetType="{x:Type RadioButton}">
+ <Setter Property="SnapsToDevicePixels" Value="true"/>
+ <Setter Property="FocusVisualStyle" Value="{DynamicResource RadioButtonFocusVisual}"/>
+ <Setter Property="Background" Value="{DynamicResource NormalBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type RadioButton}">
+
+ <!-- BulletDecorator is used to provide baseline alignment between the checkmark and the Content -->
+ <BulletDecorator Background="Transparent">
+ <BulletDecorator.Bullet>
+ <Grid Width="13" Height="13">
+ <Ellipse x:Name="Ellipse_Border" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="1"/>
+ <Ellipse Margin="4" x:Name="CheckMark" Fill="{DynamicResource GlyphBrush}"/>
+ </Grid>
+ </BulletDecorator.Bullet>
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
+ </BulletDecorator>
+
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsChecked" Value="false">
+ <Setter Property="Visibility" Value="Collapsed" TargetName="CheckMark"/>
+ </Trigger>
+ <Trigger Property="IsMouseOver" Value="true">
+ <Setter Property="Fill" Value="{DynamicResource MouseOverBrush}" TargetName="Ellipse_Border"/>
+ </Trigger>
+ <Trigger Property="IsPressed" Value="true">
+ <Setter Property="Fill" Value="{DynamicResource PressedBrush}" TargetName="Ellipse_Border"/>
+ <Setter Property="Stroke" Value="{DynamicResource GlyphBrush}" TargetName="Ellipse_Border"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Fill" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Ellipse_Border"/>
+ <Setter Property="Stroke" Value="#40000000" TargetName="Ellipse_Border"/>
+ <Setter Property="Foreground" Value="#80000000"/>
+ </Trigger>
+
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple Repeat Button - This is used by Simple ScrollBar for the up and down buttons -->
+ <Style x:Key="SimpleRepeatButton" d:IsControlPart="True" TargetType="{x:Type RepeatButton}" BasedOn="{x:Null}">
+ <Setter Property="Background" Value="{DynamicResource NormalBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type RepeatButton}">
+ <Grid>
+ <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
+ <ContentPresenter HorizontalAlignment="Center" x:Name="ContentPresenter" VerticalAlignment="Center" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsKeyboardFocused" Value="true">
+ <Setter Property="BorderBrush" Value="{DynamicResource DefaultedBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsMouseOver" Value="true">
+ <Setter Property="Background" Value="{DynamicResource MouseOverBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsPressed" Value="true">
+ <Setter Property="Background" Value="{DynamicResource PressedBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource PressedBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple Thumb - The Thumb is the draggable part of the Scrollbar -->
+ <Style x:Key="SimpleThumbStyle" d:IsControlPart="True" TargetType="{x:Type Thumb}" BasedOn="{x:Null}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Thumb}">
+ <Grid Margin="0,0,0,0" x:Name="Grid">
+ <Rectangle HorizontalAlignment="Stretch" x:Name="Rectangle" VerticalAlignment="Stretch" Width="Auto" Height="Auto" RadiusX="2" RadiusY="2" Fill="{DynamicResource NormalBrush}" Stroke="{DynamicResource NormalBorderBrush}"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsFocused" Value="True"/>
+ <Trigger Property="IsMouseOver" Value="True"/>
+ <Trigger Property="IsEnabled" Value="False"/>
+ <Trigger Property="IsDragging" Value="True"/>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple ScrollRepeatButton Style - This RepeatButton is used above and below the Thumb in the Scrollbar. They are set to transparent si that they do not show over the scrollbar -->
+ <Style x:Key="SimpleScrollRepeatButtonStyle" d:IsControlPart="True" TargetType="{x:Type RepeatButton}">
+ <Setter Property="Background" Value="Transparent"/>
+ <Setter Property="BorderBrush" Value="Transparent"/>
+ <Setter Property="IsTabStop" Value="false"/>
+ <Setter Property="Focusable" Value="false"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type RepeatButton}">
+ <Grid>
+ <Rectangle Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{TemplateBinding BorderThickness}"/>
+ </Grid>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple ScrollBar This makes use of SimpleThumb, SimpleRepeatButton and SimpleScrollRepeatButton -->
+
+ <Style x:Key="SimpleScrollBar" TargetType="{x:Type ScrollBar}">
+ <Setter Property="Stylus.IsFlicksEnabled" Value="false"/>
+ <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ScrollBar}">
+ <Grid x:Name="GridRoot" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Background="{TemplateBinding Background}">
+ <Grid.RowDefinitions>
+ <RowDefinition MaxHeight="18"/>
+ <RowDefinition Height="0.00001*"/>
+ <RowDefinition MaxHeight="18"/>
+ </Grid.RowDefinitions>
+
+ <RepeatButton x:Name="DecreaseRepeat" Style="{DynamicResource SimpleRepeatButton}" Command="ScrollBar.LineUpCommand">
+ <Grid>
+ <Path x:Name="DecreaseArrow" Stroke="{TemplateBinding Foreground}" StrokeThickness="1" Data="M 0 4 L 8 4 L 4 0 Z"/>
+ </Grid>
+ </RepeatButton>
+
+ <!-- Track is a special layout container which sizes the thumb and the repeat button which do jump scrolling either side of it -->
+ <Track Grid.Row="1" x:Name="PART_Track" Orientation="Vertical" IsDirectionReversed="true">
+ <Track.Thumb>
+ <Thumb Style="{DynamicResource SimpleThumbStyle}"/>
+ </Track.Thumb>
+ <Track.IncreaseRepeatButton>
+ <RepeatButton x:Name="PageUp" Style="{DynamicResource SimpleScrollRepeatButtonStyle}" Command="ScrollBar.PageDownCommand"/>
+ </Track.IncreaseRepeatButton>
+ <Track.DecreaseRepeatButton>
+ <RepeatButton x:Name="PageDown" Style="{DynamicResource SimpleScrollRepeatButtonStyle}" Command="ScrollBar.PageUpCommand"/>
+ </Track.DecreaseRepeatButton>
+ </Track>
+
+ <RepeatButton Grid.Row="2" x:Name="IncreaseRepeat" Style="{DynamicResource SimpleRepeatButton}" Command="ScrollBar.LineDownCommand">
+ <Grid>
+ <Path x:Name="IncreaseArrow" Stroke="{TemplateBinding Foreground}" StrokeThickness="1" Data="M 0 0 L 4 4 L 8 0 Z"/>
+ </Grid>
+ </RepeatButton>
+ </Grid>
+
+ <!-- This uses a single template for ScrollBar and rotate it to be Horizontal
+ It also changes the commands so that the it does Left and Right instead of Up and Down Commands -->
+ <ControlTemplate.Triggers>
+ <Trigger Property="Orientation" Value="Horizontal">
+
+ <!-- Rotate the ScrollBar from Vertical to Horizontal -->
+ <Setter Property="LayoutTransform" TargetName="GridRoot">
+ <Setter.Value>
+ <RotateTransform Angle="-90"/>
+ </Setter.Value>
+ </Setter>
+
+ <!-- Track is bound to Orientation internally, so we need to rotate it back to Vertical -->
+ <Setter TargetName="PART_Track" Property="Orientation" Value="Vertical"/>
+
+ <!-- Change the commands to do Horizontal commands -->
+ <Setter Property="Command" Value="ScrollBar.LineLeftCommand" TargetName="DecreaseRepeat"/>
+ <Setter Property="Command" Value="ScrollBar.LineRightCommand" TargetName="IncreaseRepeat"/>
+ <Setter Property="Command" Value="ScrollBar.PageLeftCommand" TargetName="PageDown"/>
+ <Setter Property="Command" Value="ScrollBar.PageRightCommand" TargetName="PageUp"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple ScrollViewer
+ ScrollViewer is a Grid control which has a ContentPresenter and a Horizontal and Vertical ScrollBar
+ It is used by ListBox, MenuItem, ComboBox, and TreeView -->
+ <Style x:Key="SimpleScrollViewer" TargetType="{x:Type ScrollViewer}" BasedOn="{x:Null}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ScrollViewer}">
+ <Grid Background="{TemplateBinding Background}">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*"/>
+ <ColumnDefinition Width="Auto"/>
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*"/>
+ <RowDefinition Height="Auto"/>
+ </Grid.RowDefinitions>
+ <ScrollContentPresenter Grid.Column="0" Grid.Row="0" Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" CanContentScroll="{TemplateBinding CanContentScroll}"/>
+
+ <!-- The visibility of the ScrollBars is controlled by the implementation fo the control -->
+ <ScrollBar Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Grid.Column="0" Grid.Row="1" x:Name="PART_HorizontalScrollBar" Style="{DynamicResource SimpleScrollBar}" Orientation="Horizontal" Value="{Binding Path=HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}" Minimum="0" Maximum="{TemplateBinding ScrollableWidth}" />
+ <ScrollBar Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Grid.Column="1" Grid.Row="0" x:Name="PART_VerticalScrollBar" Style="{DynamicResource SimpleScrollBar}" Orientation="Vertical" Value="{Binding Path=VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}" Minimum="0" Maximum="{TemplateBinding ScrollableHeight}" />
+ </Grid>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple ListBox - This uses SimpleScrollViewer to allow items to be scrolled and SimpleListBoxItem to define the look of each item -->
+ <Style x:Key="SimpleListBox" TargetType="{x:Type ListBox}">
+ <Setter Property="SnapsToDevicePixels" Value="true"/>
+ <Setter Property="Background" Value="{DynamicResource WindowBackgroundBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource SolidBorderBrush}"/>
+ <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
+ <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
+ <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ListBox}">
+ <Grid>
+ <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
+ <ScrollViewer Margin="1" Style="{DynamicResource SimpleScrollViewer}" Focusable="false" Background="{TemplateBinding Background}">
+
+ <!-- The StackPanel is used to display the children by setting IsItemsHost to be Trus -->
+ <StackPanel Margin="2" IsItemsHost="true"/>
+
+ </ScrollViewer>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsGrouping" Value="true">
+ <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple ListBoxItem - This is used for each Item in a ListBox. The item's content is placed in the ContentPresenter -->
+
+ <Style x:Key="SimpleListBoxItem" d:IsControlPart="True" TargetType="{x:Type ListBoxItem}">
+ <Setter Property="SnapsToDevicePixels" Value="true"/>
+ <Setter Property="OverridesDefaultStyle" Value="true"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ListBoxItem}">
+ <Grid SnapsToDevicePixels="true">
+ <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+
+ <!-- Change IsSelected SelectedBackgroundBrush to set the selection color for the items -->
+ <Trigger Property="IsSelected" Value="true">
+ <Setter Property="Background" Value="{DynamicResource SelectedBackgroundBrush}" TargetName="Border"/>
+ </Trigger>
+
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple Expander ToggleButton - This Button is used by the Expander control. When it is toggled it switches visibility on the Up_Arrow and Down_Arrow -->
+ <ControlTemplate x:Key="ExpanderToggleButton" TargetType="{x:Type ToggleButton}">
+ <Grid>
+ <Rectangle Margin="0,0,0,0" x:Name="Rectangle" Fill="Transparent" Stroke="{DynamicResource NormalBorderBrush}"/>
+ <Path HorizontalAlignment="Center" x:Name="Up_Arrow" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 0 0 L 4 4 L 8 0 Z"/>
+ <Path Visibility="Collapsed" HorizontalAlignment="Center" x:Name="Down_Arrow" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 0 4 L 4 0 L 8 4 Z"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsMouseOver" Value="true">
+ <Setter Property="Fill" Value="{DynamicResource MouseOverBrush}" TargetName="Rectangle"/>
+ </Trigger>
+ <Trigger Property="IsPressed" Value="true">
+ <Setter Property="Fill" Value="{DynamicResource PressedBrush}" TargetName="Rectangle"/>
+ </Trigger>
+ <Trigger Property="IsChecked" Value="true">
+ <Setter Property="Visibility" Value="Visible" TargetName="Down_Arrow"/>
+ <Setter Property="Visibility" Value="Collapsed" TargetName="Up_Arrow"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Fill" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Rectangle"/>
+ <Setter Property="Stroke" Value="{DynamicResource DisabledBorderBrush}" TargetName="Rectangle"/>
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ <Setter Property="Fill" Value="{DynamicResource DisabledForegroundBrush}" TargetName="Up_Arrow"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+
+ <!-- Simple Expander
+ This uses the Simpler ExpanderToggleButton. It sets Visibility on the ContentPresenter to expand
+ Limitations : The Simple Expander only expands down -->
+ <Style x:Key="SimpleExpander" TargetType="{x:Type Expander}">
+ <Setter Property="Background" Value="{DynamicResource LightBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Expander}">
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*" x:Name="ContentRow"/>
+ </Grid.RowDefinitions>
+ <Border Grid.Row="0" x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2,2,0,0">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="20"/>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+ <ToggleButton Template="{DynamicResource ExpanderToggleButton}" Background="{DynamicResource NormalBrush}" IsChecked="{Binding Path=IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" OverridesDefaultStyle="True"/>
+ <ContentPresenter Grid.Column="1" Margin="4" RecognizesAccessKey="True" ContentSource="Header"/>
+ </Grid>
+ </Border>
+ <Border Visibility="Collapsed" Grid.Row="1" x:Name="ExpandSite" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1,0,1,1" CornerRadius="0,0,2,2">
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Focusable="false"/>
+ </Border>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsExpanded" Value="True">
+ <Setter Property="Visibility" Value="Visible" TargetName="ExpandSite"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple ComboBox Toggle Button - This is used in ComboBox to expand and collapse the ComboBox Popup-->
+ <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition/>
+ <ColumnDefinition Width="20"/>
+ </Grid.ColumnDefinitions>
+ <Rectangle Grid.ColumnSpan="2" HorizontalAlignment="Stretch" x:Name="Rectangle" VerticalAlignment="Stretch" Width="Auto" Height="Auto" RadiusX="5" RadiusY="5" Fill="{DynamicResource NormalBrush}" Stroke="{DynamicResource NormalBorderBrush}"/>
+ <Rectangle Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" RadiusX="5" RadiusY="5" Fill="{DynamicResource WindowBackgroundBrush}" Stroke="{DynamicResource NormalBorderBrush}"/>
+ <Path Grid.Column="1" HorizontalAlignment="Center" x:Name="Arrow" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 0 0 L 4 4 L 8 0 Z"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsMouseOver" Value="true">
+ <Setter Property="Fill" Value="{DynamicResource MouseOverBrush}" TargetName="Rectangle"/>
+ </Trigger>
+ <Trigger Property="IsChecked" Value="true">
+ <Setter Property="Fill" Value="{DynamicResource PressedBrush}" TargetName="Rectangle"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Fill" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Rectangle"/>
+ <Setter Property="Stroke" Value="{DynamicResource DisabledBorderBrush}" TargetName="Rectangle"/>
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ <Setter Property="Fill" Value="{DynamicResource DisabledForegroundBrush}" TargetName="Arrow"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+
+ <!-- This is the area which contains the selected item in the ComboBox -->
+
+ <ControlTemplate x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}">
+ <!-- This must be named as PART_ContentHost -->
+ <Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}"/>
+ </ControlTemplate>
+
+ <!-- Simple ComboBox
+ This uses the ComboBoxToggleButton to expand and collapse a Popup control
+ SimpleScrollViewer to allow items to be scrolled and SimpleComboBoxItem to define the look of each item
+ The Popup shows a list of items in a StackPanel-->
+
+ <Style x:Key="SimpleComboBox" TargetType="{x:Type ComboBox}">
+ <Setter Property="SnapsToDevicePixels" Value="true"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ComboBox}">
+ <Grid>
+ <!-- The ToggleButton is databound to the ComboBox itself to toggle IsDropDownOpen -->
+ <ToggleButton Grid.Column="2" Template="{DynamicResource ComboBoxToggleButton}" x:Name="ToggleButton" Focusable="false" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/>
+ <ContentPresenter HorizontalAlignment="Left" Margin="3,3,23,3" x:Name="ContentSite" VerticalAlignment="Center" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" IsHitTestVisible="False"/>
+
+ <!-- The TextBox must be named PART_EditableTextBox or ComboBox will not recognize it -->
+ <TextBox Visibility="Hidden" Template="{DynamicResource ComboBoxTextBox}" HorizontalAlignment="Left" Margin="3,3,23,3" x:Name="PART_EditableTextBox" Style="{x:Null}" VerticalAlignment="Center" Focusable="True" Background="Transparent" IsReadOnly="{TemplateBinding IsReadOnly}"/>
+
+ <!-- The Popup shows the list of items in the ComboBox. IsOpen is databound to IsDropDownOpen which is toggled via the ComboBoxToggleButton -->
+ <Popup IsOpen="{TemplateBinding IsDropDownOpen}" Placement="Bottom" x:Name="Popup" Focusable="False" AllowsTransparency="True" PopupAnimation="Slide">
+ <Grid MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{TemplateBinding ActualWidth}" x:Name="DropDown" SnapsToDevicePixels="True">
+ <Border x:Name="DropDownBorder" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1"/>
+ <ScrollViewer Margin="4,6,4,6" Style="{DynamicResource SimpleScrollViewer}" SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="True">
+
+ <!-- The StackPanel is used to display the children by setting IsItemsHost to be True -->
+ <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained"/>
+
+ </ScrollViewer>
+ </Grid>
+ </Popup>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <!-- This forces the DropDown to have a minimum size if it is empty -->
+ <Trigger Property="HasItems" Value="false">
+ <Setter Property="MinHeight" Value="95" TargetName="DropDownBorder"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ </Trigger>
+ <Trigger Property="IsGrouping" Value="true">
+ <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
+ </Trigger>
+ <Trigger Property="AllowsTransparency" SourceName="Popup" Value="true">
+ <Setter Property="CornerRadius" Value="4" TargetName="DropDownBorder"/>
+ <Setter Property="Margin" Value="0,2,0,0" TargetName="DropDownBorder"/>
+ </Trigger>
+ <Trigger Property="IsEditable" Value="true">
+ <Setter Property="IsTabStop" Value="false"/>
+ <Setter Property="Visibility" Value="Visible" TargetName="PART_EditableTextBox"/>
+ <Setter Property="Visibility" Value="Hidden" TargetName="ContentSite"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple ComboBoxItem - This is used for each item inside of the ComboBox. You can change the selected color of each item below-->
+ <Style x:Key="SimpleComboBoxItem" d:IsControlPart="True" TargetType="{x:Type ComboBoxItem}">
+ <Setter Property="SnapsToDevicePixels" Value="true"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ComboBoxItem}">
+ <Grid SnapsToDevicePixels="true">
+ <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+
+ <!-- Change IsHighlighted SelectedBackgroundBrush to set the selection color for the items -->
+ <Trigger Property="IsHighlighted" Value="true">
+ <Setter Property="Background" Value="{DynamicResource SelectedBackgroundBrush}" TargetName="Border"/>
+ </Trigger>
+
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple SimpleProgressBar
+ The template uses two Border controls to show the Track and Progress
+ Limitations : It only supports a horizontal orientated ProgressBar -->
+ <Style x:Key="SimpleProgressBar" TargetType="{x:Type ProgressBar}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ProgressBar}">
+ <Grid>
+
+ <!-- This Border is the track. It must be named PART_Track -->
+ <Border x:Name="PART_Track" Background="{DynamicResource PressedBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="2"/>
+
+ <!-- This Border shows progress. It must be named PART_Indicator for the control to function -->
+ <Border HorizontalAlignment="Left" x:Name="PART_Indicator" Background="{DynamicResource MouseOverBrush}" BorderBrush="{DynamicResource NormalBorderBrush}" BorderThickness="1" CornerRadius="2"/>
+
+ </Grid>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple TextBox -->
+ <Style x:Key="SimpleTextBox" TargetType="{x:Type TextBox}">
+ <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
+ <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
+ <Setter Property="AllowDrop" Value="true"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type TextBox}">
+ <Grid>
+ <Border x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" Padding="2" CornerRadius="2">
+
+ <!-- The implementation places the Content into the ScrollViewer. It must be named PART_ContentHost for the control to function -->
+ <ScrollViewer Margin="0" x:Name="PART_ContentHost" Style="{DynamicResource SimpleScrollViewer}" Background="{TemplateBinding Background}"/>
+
+ </Border>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple Label - This template is just a ContentPresenter that shows the content of the Label -->
+ <Style x:Key="SimpleLabel" TargetType="{x:Type Label}">
+ <Setter Property="HorizontalContentAlignment" Value="Left"/>
+ <Setter Property="VerticalContentAlignment" Value="Top"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Label}">
+ <Grid>
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsEnabled" Value="false"/>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple Menu - This template uses a StackPanel to layout MenuItems -->
+ <Style x:Key="SimpleMenu" TargetType="{x:Type Menu}">
+ <Setter Property="Background" Value="{DynamicResource LightBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
+ <Setter Property="SnapsToDevicePixels" Value="True"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Menu}">
+ <Grid>
+ <Border Margin="1" x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
+ <StackPanel Background="{TemplateBinding Background}" IsItemsHost="True" ClipToBounds="True" Orientation="Horizontal"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- This BitmapEffect is used by the Simple MenuItem -->
+ <DropShadowBitmapEffect x:Key="PopupDropShadow" ShadowDepth="1.5" Softness="0.15"/>
+
+ <!-- Simple MenuItem - The template uses triggers to provide four different arrangements of menu item which are set via the Role property -->
+ <Style x:Key="SimpleMenuItem" TargetType="{x:Type MenuItem}">
+ <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
+ <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
+ <Setter Property="Background" Value="Transparent"/>
+ <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.MenuTextBrushKey}}"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type MenuItem}">
+ <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
+ <Grid>
+
+ <!-- The Grid is used to hold together columns for an Icon, Content, Glyph checkmark and Arrow to show the next level
+ Size sharing is used in Grid so that the Icon, Content, Arrow for each MenuItem align together -->
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition MinWidth="17" Width="Auto" SharedSizeGroup="MenuItemIconColumnGroup"/>
+ <ColumnDefinition Width="*"/>
+ <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIGTColumnGroup"/>
+ <ColumnDefinition Width="14"/>
+ </Grid.ColumnDefinitions>
+
+ <!-- ContentPresenter to show an Icon if needed -->
+ <ContentPresenter Margin="4,0,6,0" x:Name="Icon" VerticalAlignment="Center" ContentSource="Icon"/>
+
+ <!-- Glyph is a checkmark if needed for a checkable menu -->
+ <Grid Visibility="Hidden" Margin="4,0,6,0" x:Name="GlyphPanel" VerticalAlignment="Center">
+ <Path x:Name="GlyphPanelpath" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,2 L0,4.8 L2.5,7.4 L7.1,2.8 L7.1,0 L2.5,4.6 z" FlowDirection="LeftToRight"/>
+ </Grid>
+
+ <!-- Content for the menu text etc -->
+ <ContentPresenter Grid.Column="1" Margin="{TemplateBinding Padding}" x:Name="HeaderHost" RecognizesAccessKey="True" ContentSource="Header"/>
+
+ <!-- Arrow drawn path which points to the next level of the menu -->
+ <Grid Grid.Column="3" Margin="4,0,6,0" x:Name="ArrowPanel" VerticalAlignment="Center">
+ <Path x:Name="ArrowPanelPath" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,0 L0,8 L4,4 z"/>
+ </Grid>
+
+ <!-- The Popup is the body of the menu which expands down or across depending on the level of the item -->
+ <Popup IsOpen="{Binding Path=IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" x:Name="SubMenuPopup" Focusable="false" AllowsTransparency="true" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" VerticalOffset="-3">
+ <Grid x:Name="SubMenu">
+ <Border x:Name="SubMenuBorder" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1"/>
+
+ <!-- StackPanel holds children of the menu. This is set bu IsItemsHost=True -->
+ <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/>
+ </Grid>
+ </Popup>
+
+ </Grid>
+ </Border>
+
+ <!-- These triggers re-configure the four arrangements of MenuItem to show different levels of menu via Role -->
+ <ControlTemplate.Triggers>
+
+ <!-- Role = TopLevelHeader : this is the root menu item in a menu; the Popup expands down -->
+ <Trigger Property="Role" Value="TopLevelHeader">
+ <Setter Property="Margin" Value="0,1,0,1"/>
+ <Setter Property="Padding" Value="6,3,6,3"/>
+ <Setter Property="Grid.IsSharedSizeScope" Value="true"/>
+ <Setter Property="Placement" Value="Bottom" TargetName="SubMenuPopup"/>
+ <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
+ </Trigger>
+
+ <!-- Role = TopLevelItem : this is a child menu item from the top level without any child items-->
+ <Trigger Property="Role" Value="TopLevelItem">
+ <Setter Property="Margin" Value="0,1,0,1"/>
+ <Setter Property="Padding" Value="6,3,6,3"/>
+ <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
+ </Trigger>
+
+ <!-- Role = SubMenuHeader : this is a child menu item which does not have children -->
+ <Trigger Property="Role" Value="SubmenuHeader">
+ <Setter Property="DockPanel.Dock" Value="Top"/>
+ <Setter Property="Padding" Value="0,2,0,2"/>
+ <Setter Property="Grid.IsSharedSizeScope" Value="true"/>
+ </Trigger>
+
+ <!-- Role = SubMenuItem : this is a child menu item which has children-->
+ <Trigger Property="Role" Value="SubmenuItem">
+ <Setter Property="DockPanel.Dock" Value="Top"/>
+ <Setter Property="Padding" Value="0,2,0,2"/>
+ <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/>
+ </Trigger>
+ <Trigger Property="IsSuspendingPopupAnimation" Value="true">
+ <Setter Property="PopupAnimation" Value="None" TargetName="SubMenuPopup"/>
+ </Trigger>
+
+ <!-- If no Icon is present the we collapse the Icon Content -->
+ <Trigger Property="Icon" Value="{x:Null}">
+ <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
+ </Trigger>
+
+ <!-- The GlyphPanel contains the CheckMark -->
+ <Trigger Property="IsChecked" Value="true">
+ <Setter Property="Visibility" Value="Visible" TargetName="GlyphPanel"/>
+ <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/>
+ </Trigger>
+
+ <Trigger Property="AllowsTransparency" SourceName="SubMenuPopup" Value="true">
+ <Setter Property="Margin" Value="0,0,3,3" TargetName="SubMenu"/>
+ <Setter Property="SnapsToDevicePixels" Value="true" TargetName="SubMenu"/>
+ <Setter Property="BitmapEffect" Value="{DynamicResource PopupDropShadow}" TargetName="SubMenuBorder"/>
+ </Trigger>
+
+ <!-- Using the system colors for the Menu Highlight and IsEnabled-->
+ <Trigger Property="IsHighlighted" Value="true">
+ <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" TargetName="Border"/>
+ <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple Separator - This template is used for a Separator in a menu -->
+ <Style x:Key="SimpleSeparator" TargetType="{x:Type Separator}">
+ <Setter Property="Height" Value="1"/>
+ <Setter Property="Margin" Value="0,2,0,2"/>
+ <Setter Property="Focusable" Value="false"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Separator}">
+ <Border BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1"/>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Simple TabControl
+ This template uses Simple TabItem for each Tab. The TabItems are placed in the TabPanel
+ Limitations : The Simple TabControl only allow the Tabs to be shown at the top of the Tab control. You can re-position the TabPanel to change this-->
+
+ <Style x:Key="SimpleTabControl" TargetType="{x:Type TabControl}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type TabControl}">
+ <Grid KeyboardNavigation.TabNavigation="Local">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+ <!-- TabPanel is a layout container which allows the TabItems to wrap and re-order when selected
+ The implementation knows to use this control because it is marked IsItemsHost = True -->
+ <TabPanel Grid.Row="0" Margin="0,0,4,-1" x:Name="HeaderPanel" Background="Transparent" IsItemsHost="True" Panel.ZIndex="1" KeyboardNavigation.TabIndex="1"/>
+
+ <Border Grid.Row="1" x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="2" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.TabIndex="2">
+
+ <!-- The implementation switches the content. This control must be named PART_SelectedContentHost -->
+ <ContentPresenter Margin="4" x:Name="PART_SelectedContentHost" ContentSource="SelectedContent"/>
+
+ </Border>
+ </Grid>
+
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!--Simple TabItem -->
+ <Style x:Key="SimpleTabItem" d:IsControlPart="True" TargetType="{x:Type TabItem}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type TabItem}">
+ <Grid>
+ <Border Margin="0,0,-4,0" x:Name="Border" Background="{DynamicResource LightBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1,1,1,1" CornerRadius="2,12,0,0">
+ <ContentPresenter HorizontalAlignment="Center" Margin="12,2,12,2" x:Name="ContentSite" VerticalAlignment="Center" RecognizesAccessKey="True" ContentSource="Header"/>
+ </Border>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Panel.ZIndex" Value="100"/>
+ <Setter Property="Background" Value="{DynamicResource WindowBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderThickness" Value="1,1,1,0" TargetName="Border"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!--Simple Simple SliderThumb - The Thumb is the draggable part of a Slider-->
+ <Style x:Key="SimpleSliderThumb" d:IsControlPart="True" TargetType="{x:Type Thumb}">
+ <Setter Property="SnapsToDevicePixels" Value="true"/>
+ <Setter Property="Height" Value="14"/>
+ <Setter Property="Width" Value="14"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Thumb}">
+ <Grid>
+ <Ellipse x:Name="Ellipse" Fill="{DynamicResource NormalBrush}" Stroke="{DynamicResource NormalBorderBrush}" StrokeThickness="1"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsMouseOver" Value="True">
+ <Setter Property="Fill" Value="{DynamicResource MouseOverBrush}" TargetName="Ellipse"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Fill" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Ellipse"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!--Simple Simple Slider
+ Similiar to ScrollBar this template uses Track to layout the draggable Thumb which has an up and down repeat button
+ It uses Simple SliderThumb and SimpleScrollRepeatButtonStyle for the page up and down repeat buttons -->
+ <Style x:Key="SimpleSlider" TargetType="{x:Type Slider}">
+ <Setter Property="Background" Value="{DynamicResource LightBrush}"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type Slider}">
+ <Grid x:Name="GridRoot">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
+ <RowDefinition Height="Auto"/>
+ </Grid.RowDefinitions>
+
+ <!-- TickBar shows the ticks for Slider -->
+ <TickBar Visibility="Collapsed" x:Name="TopTick" Height="4" SnapsToDevicePixels="True" Placement="Top" Fill="{DynamicResource GlyphBrush}"/>
+ <Border Grid.Row="1" Margin="0" x:Name="Border" Height="4" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/>
+
+ <!-- The Track lays out the repeat buttons and thumb -->
+ <Track Grid.Row="1" x:Name="PART_Track">
+ <Track.Thumb>
+ <Thumb Style="{DynamicResource SimpleSliderThumb}"/>
+ </Track.Thumb>
+ <Track.IncreaseRepeatButton>
+ <RepeatButton Style="{DynamicResource SimpleScrollRepeatButtonStyle}" Command="Slider.IncreaseLarge"/>
+ </Track.IncreaseRepeatButton>
+ <Track.DecreaseRepeatButton>
+ <RepeatButton Style="{DynamicResource SimpleScrollRepeatButtonStyle}" Command="Slider.DecreaseLarge"/>
+ </Track.DecreaseRepeatButton>
+ </Track>
+
+ <TickBar Visibility="Collapsed" Grid.Row="2" x:Name="BottomTick" Height="4" SnapsToDevicePixels="True" Placement="Bottom" Fill="{TemplateBinding Foreground}"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="TickPlacement" Value="TopLeft">
+ <Setter Property="Visibility" Value="Visible" TargetName="TopTick"/>
+ </Trigger>
+ <Trigger Property="TickPlacement" Value="BottomRight">
+ <Setter Property="Visibility" Value="Visible" TargetName="BottomTick"/>
+ </Trigger>
+ <Trigger Property="TickPlacement" Value="Both">
+ <Setter Property="Visibility" Value="Visible" TargetName="TopTick"/>
+ <Setter Property="Visibility" Value="Visible" TargetName="BottomTick"/>
+ </Trigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
+ <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
+ </Trigger>
+
+ <!-- Use a rotation to create a Vertical Slider form the default Horizontal -->
+ <Trigger Property="Orientation" Value="Vertical">
+ <Setter Property="LayoutTransform" TargetName="GridRoot">
+ <Setter.Value>
+ <RotateTransform Angle="-90"/>
+ </Setter.Value>
+ </Setter>
+ <!-- Track rotates itself based on orientation so need to force it back -->
+ <Setter TargetName="PART_Track" Property="Orientation" Value="Horizontal"/>
+ </Trigger>
+
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!--Simple Tree View - This lays out TreeViewItems within a ScrollViewer -->
+ <Style x:Key="SimpleTreeView" TargetType="{x:Type TreeView}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type TreeView}">
+ <Grid>
+ <Border x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="1">
+ <ScrollViewer Style="{DynamicResource SimpleScrollViewer}" Focusable="False" Background="{TemplateBinding Background}" Padding="4" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="False">
+ <ItemsPresenter/>
+ </ScrollViewer>
+ </Border>
+ </Grid>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!--Simple TreeViewItem ToggleButton - + and - button to expand and collapse a TreeViewItem -->
+ <Style x:Key="SimpleTreeViewItemToggleButton" d:IsControlPart="True" TargetType="{x:Type ToggleButton}">
+ <Setter Property="Focusable" Value="False"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ToggleButton}">
+ <Grid Width="15" Height="13" Background="Transparent">
+ <Path Visibility="Collapsed" HorizontalAlignment="Left" Margin="1,1,1,1" x:Name="IsExpandedPath" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 0 4 L 8 4 L 4 8 Z"/>
+ <Path HorizontalAlignment="Left" Margin="1,1,1,1" x:Name="ExpandPath" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 4 0 L 8 4 L 4 8 Z"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsChecked" Value="True">
+ <Setter Property="Visibility" Value="Visible" TargetName="IsExpandedPath"/>
+ <Setter Property="Visibility" Value="Collapsed" TargetName="ExpandPath"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!--Simple TreeViewItem - The TreeViewItem template has a header which shows the Item and a Body which is an ItemsHost control which expands to show child items-->
+ <Style x:Key="SimpleTreeViewItem" d:IsControlPart="True" TargetType="{x:Type TreeViewItem}">
+ <Setter Property="Background" Value="Transparent"/>
+ <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
+ <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
+ <Setter Property="Padding" Value="1,0,0,0"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type TreeViewItem}">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition MinWidth="19" Width="Auto"/>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition/>
+ </Grid.RowDefinitions>
+ <ToggleButton x:Name="Expander" Style="{DynamicResource SimpleTreeViewItemToggleButton}" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/>
+ <Border Grid.Column="1" x:Name="Selection_Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" x:Name="PART_Header" ContentSource="Header"/>
+ </Border>
+ <ItemsPresenter Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" x:Name="ItemsHost"/>
+ </Grid>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsExpanded" Value="false">
+ <Setter Property="Visibility" Value="Collapsed" TargetName="ItemsHost"/>
+ </Trigger>
+ <Trigger Property="HasItems" Value="false">
+ <Setter Property="Visibility" Value="Hidden" TargetName="Expander"/>
+ </Trigger>
+ <Trigger Property="IsSelected" Value="true">
+ <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" TargetName="Selection_Border"/>
+ <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
+ </Trigger>
+ <MultiTrigger>
+ <MultiTrigger.Conditions>
+ <Condition Property="IsSelected" Value="true"/>
+ <Condition Property="IsSelectionActive" Value="false"/>
+ </MultiTrigger.Conditions>
+ <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" TargetName="Selection_Border"/>
+ <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
+ </MultiTrigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+</ResourceDictionary>
diff --git a/windows/WinUI/Themes/Generic.xaml b/windows/WinUI/Themes/Generic.xaml
new file mode 100644
index 00000000..2b47588d
--- /dev/null
+++ b/windows/WinUI/Themes/Generic.xaml
@@ -0,0 +1,7 @@
+<ResourceDictionary
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="clr-namespace:WinUI">
+
+
+</ResourceDictionary>
diff --git a/windows/WebUIWrapper/WebUIWrapper.csproj b/windows/WinUI/WinUI.csproj
index 44fef263..c3eeaba4 100644
--- a/windows/WebUIWrapper/WebUIWrapper.csproj
+++ b/windows/WinUI/WinUI.csproj
@@ -4,13 +4,17 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{04832129-0F0C-438B-ACDF-8BB7F99AE241}</ProjectGuid>
+ <ProjectGuid>{4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>WebUIWrapper</RootNamespace>
+ <RootNamespace>WinUI</RootNamespace>
<AssemblyName>ZeroTier One</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ <ExpressionBlendVersion>5.0.40218.0</ExpressionBlendVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@@ -21,9 +25,9 @@
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
+ <AutorunEnabled>true</AutorunEnabled>
<ApplicationRevision>0</ApplicationRevision>
- <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
- <IsWebBootstrapper>false</IsWebBootstrapper>
+ <ApplicationVersion>1.0.0.0</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
@@ -36,79 +40,137 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
- <DefineConstants>
- </DefineConstants>
+ <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
- <StartupObject>WebUIWrapper.Program</StartupObject>
- </PropertyGroup>
- <PropertyGroup>
- <SignAssembly>false</SignAssembly>
+ <StartupObject>WinUI.App</StartupObject>
</PropertyGroup>
<PropertyGroup>
- <TargetZone>LocalIntranet</TargetZone>
+ <ApplicationIcon>ZeroTierIcon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
- <GenerateManifests>false</GenerateManifests>
+ <SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup>
- <ApplicationManifest>Properties\app.manifest</ApplicationManifest>
+ <SignManifests>false</SignManifests>
</PropertyGroup>
<PropertyGroup>
- <ApplicationIcon>ZeroTierIcon.ico</ApplicationIcon>
+ <ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="Accessibility" />
+ <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="PresentationUI, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ <Reference Include="ReachFramework" />
<Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="System.Xml.Linq" />
- <Reference Include="System.Data.DataSetExtensions" />
- <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
+ <Reference Include="System.Printing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Xaml">
+ <RequiredTargetFramework>4.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="UIAutomationProvider" />
+ <Reference Include="UIAutomationTypes" />
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
- <Compile Include="Form1.cs">
- <SubType>Form</SubType>
+ <ApplicationDefinition Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </ApplicationDefinition>
+ <Compile Include="NetworksPage.xaml.cs">
+ <DependentUpon>NetworksPage.xaml</DependentUpon>
</Compile>
- <Compile Include="Form1.Designer.cs">
- <DependentUpon>Form1.cs</DependentUpon>
+ <Compile Include="PeersPage.xaml.cs">
+ <DependentUpon>PeersPage.xaml</DependentUpon>
</Compile>
- <Compile Include="Program.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <EmbeddedResource Include="Form1.resx">
- <DependentUpon>Form1.cs</DependentUpon>
- </EmbeddedResource>
- <EmbeddedResource Include="Properties\Resources.resx">
- <Generator>ResXFileCodeGenerator</Generator>
- <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ <Compile Include="ZeroTierPeerPhysicalPath.cs" />
+ <Compile Include="ZeroTierPeer.cs" />
+ <Compile Include="ZeroTierNetwork.cs" />
+ <Compile Include="ZeroTierStatus.cs" />
+ <Page Include="MainWindow.xaml">
+ <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
- </EmbeddedResource>
+ </Page>
+ <Compile Include="APIHandler.cs" />
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="MainWindow.xaml.cs">
+ <DependentUpon>MainWindow.xaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Page Include="NetworkInfoView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="NetworksPage.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="PeersPage.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Simple Styles.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Themes\Generic.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="NetworkInfoView.xaml.cs">
+ <DependentUpon>NetworkInfoView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
- <DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
</Compile>
- <None Include="Properties\app.manifest" />
- <None Include="Properties\Settings.settings">
- <Generator>SettingsSingleFileGenerator</Generator>
- <LastGenOutput>Settings.Designer.cs</LastGenOutput>
- </None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="app.manifest" />
+ <None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ <AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
@@ -131,9 +193,30 @@
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
- <Content Include="ZeroTierIcon.ico" />
+ <BlendEmbeddedFont Include="Fonts\segoeui.ttf">
+ <IsSystemFont>True</IsSystemFont>
+ <All>True</All>
+ <AutoFill>True</AutoFill>
+ </BlendEmbeddedFont>
+ <BlendEmbeddedFont Include="Fonts\segoeuib.ttf">
+ <IsSystemFont>True</IsSystemFont>
+ <All>True</All>
+ <AutoFill>True</AutoFill>
+ </BlendEmbeddedFont>
+ <BlendEmbeddedFont Include="Fonts\segoeuii.ttf">
+ <IsSystemFont>True</IsSystemFont>
+ <All>True</All>
+ <AutoFill>True</AutoFill>
+ </BlendEmbeddedFont>
+ <BlendEmbeddedFont Include="Fonts\segoeuiz.ttf">
+ <IsSystemFont>True</IsSystemFont>
+ <All>True</All>
+ <AutoFill>True</AutoFill>
+ </BlendEmbeddedFont>
+ <Resource Include="ZeroTierIcon.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Expression\Blend\.NETFramework\v4.5\Microsoft.Expression.Blend.WPF.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
diff --git a/windows/WebUIWrapper/ZeroTierIcon.ico b/windows/WinUI/ZeroTierIcon.ico
index 2d190c47..2d190c47 100644
--- a/windows/WebUIWrapper/ZeroTierIcon.ico
+++ b/windows/WinUI/ZeroTierIcon.ico
Binary files differ
diff --git a/windows/WinUI/ZeroTierNetwork.cs b/windows/WinUI/ZeroTierNetwork.cs
new file mode 100644
index 00000000..cce65441
--- /dev/null
+++ b/windows/WinUI/ZeroTierNetwork.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace WinUI
+{
+ public class ZeroTierNetwork
+ {
+ [JsonProperty("nwid")]
+ public string NetworkId { get; set; }
+
+ [JsonProperty("mac")]
+ public string MacAddress { get; set; }
+
+ [JsonProperty("name")]
+ public string NetworkName { get; set; }
+
+ [JsonProperty("status")]
+ public string NetworkStatus { get; set; }
+
+ [JsonProperty("type")]
+ public string NetworkType { get; set; }
+
+ [JsonProperty("mtu")]
+ public int MTU { get; set; }
+
+ [JsonProperty("dhcp")]
+ public bool DHCP { get; set; }
+
+ [JsonProperty("bridge")]
+ public bool Bridge { get; set ; }
+
+ [JsonProperty("broadcastEnabled")]
+ public bool BroadcastEnabled { get ; set; }
+
+ [JsonProperty("portError")]
+ public int PortError { get; set; }
+
+ [JsonProperty("netconfRevision")]
+ public int NetconfRevision { get; set; }
+
+ [JsonProperty("multicastSubscriptions")]
+ public string[] MulticastSubscriptions { get; set; }
+
+ [JsonProperty("assignedAddresses")]
+ public string[] AssignedAddresses { get; set; }
+
+ [JsonProperty("portDeviceName")]
+ public string DeviceName { get; set; }
+ }
+}
diff --git a/windows/WinUI/ZeroTierPeer.cs b/windows/WinUI/ZeroTierPeer.cs
new file mode 100644
index 00000000..1597cf2d
--- /dev/null
+++ b/windows/WinUI/ZeroTierPeer.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace WinUI
+{
+ public class ZeroTierPeer : IEquatable<ZeroTierPeer>
+ {
+ [JsonProperty("address")]
+ public string Address { get; set; }
+
+ private Int64 _lastUnicast;
+ [JsonProperty("lastUnicastFrame")]
+ public Int64 LastUnicastFrame
+ {
+ get
+ {
+ if (_lastUnicast == 0)
+ return 0;
+
+ TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
+ Int64 millisecondsSinceEpoch = (Int64)t.TotalMilliseconds;
+ return (millisecondsSinceEpoch - _lastUnicast) / 1000;
+ }
+ set
+ {
+ _lastUnicast = value;
+ }
+ }
+
+ private Int64 _lastMulticast;
+ [JsonProperty("lastMulticastFrame")]
+ public Int64 LastMulticastFrame
+ {
+ get
+ {
+ if (_lastMulticast == 0)
+ return 0;
+
+ TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
+ Int64 millisecondsSinceEpoch = (Int64)t.TotalMilliseconds;
+ return (millisecondsSinceEpoch - _lastMulticast) / 1000;
+ }
+ set
+ {
+ _lastMulticast = value;
+ }
+ }
+
+ [JsonProperty("versionMajor")]
+ public int VersionMajor { get; set; }
+
+ [JsonProperty("versionMinor")]
+ public int VersionMinor { get; set; }
+
+ [JsonProperty("versionRev")]
+ public int VersionRev { get; set; }
+
+ [JsonProperty("version")]
+ public string Version { get; set; }
+
+ public string VersionString
+ {
+ get
+ {
+ if (Version == "-1.-1.-1")
+ return "-";
+ else
+ return Version;
+ }
+ }
+
+ [JsonProperty("latency")]
+ public string Latency { get; set; }
+
+ [JsonProperty("role")]
+ public string Role { get; set; }
+
+ [JsonProperty("paths")]
+ public List<ZeroTierPeerPhysicalPath> Paths { get; set; }
+
+ public string DataPaths
+ {
+ get
+ {
+ string pathStr = "";
+ foreach(ZeroTierPeerPhysicalPath path in Paths)
+ {
+ pathStr += path.Address + "\n";
+ }
+ return pathStr;
+ }
+ }
+
+ public bool Equals(ZeroTierPeer other)
+ {
+ return this.Address.Equals(other.Address, StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ public void Update(ZeroTierPeer other)
+ {
+ _lastUnicast = other._lastUnicast;
+ _lastMulticast = other._lastMulticast;
+ VersionMajor = other.VersionMajor;
+ VersionMinor = other.VersionMinor;
+ VersionRev = other.VersionRev;
+ Version = other.Version;
+ Latency = other.Latency;
+ Role = other.Role;
+ Paths = other.Paths;
+ }
+ }
+}
diff --git a/windows/WinUI/ZeroTierPeerPhysicalPath.cs b/windows/WinUI/ZeroTierPeerPhysicalPath.cs
new file mode 100644
index 00000000..3eaa8026
--- /dev/null
+++ b/windows/WinUI/ZeroTierPeerPhysicalPath.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace WinUI
+{
+ public class ZeroTierPeerPhysicalPath
+ {
+ [JsonProperty("address")]
+ public string Address { get; set; }
+
+ [JsonProperty("lastSend")]
+ public UInt64 LastSend { get; set; }
+
+ [JsonProperty("lastReceive")]
+ public UInt64 LastReceive { get; set; }
+
+ [JsonProperty("fixed")]
+ public bool Fixed { get; set; }
+
+ [JsonProperty("preferred")]
+ public bool Preferred { get; set; }
+ }
+}
diff --git a/windows/WinUI/ZeroTierStatus.cs b/windows/WinUI/ZeroTierStatus.cs
new file mode 100644
index 00000000..2851d017
--- /dev/null
+++ b/windows/WinUI/ZeroTierStatus.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace WinUI
+{
+ public class ZeroTierStatus
+ {
+ [JsonProperty("address")]
+ public string Address { get; set; }
+
+ [JsonProperty("publicIdentity")]
+ public string PublicIdentity { get; set; }
+
+ [JsonProperty("online")]
+ public bool Online { get; set; }
+
+ [JsonProperty("tcpFallbackActive")]
+ public bool TcpFallbackActive { get; set; }
+
+ [JsonProperty("versionMajor")]
+ public int VersionMajor { get; set; }
+
+ [JsonProperty("versionMinor")]
+ public int VersionMinor { get; set; }
+
+ [JsonProperty("versionRev")]
+ public int VersionRev { get; set; }
+
+ [JsonProperty("version")]
+ public string Version { get; set; }
+
+ [JsonProperty("clock")]
+ public UInt64 Clock { get; set; }
+ }
+}
diff --git a/windows/WebUIWrapper/Properties/app.manifest b/windows/WinUI/app.manifest
index 4e1881fb..b537bf49 100644
--- a/windows/WebUIWrapper/Properties/app.manifest
+++ b/windows/WinUI/app.manifest
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
+ <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
@@ -18,24 +18,26 @@
-->
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
- <applicationRequestMinimum>
- <defaultAssemblyRequest permissionSetReference="Custom" />
- <PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" />
- </applicationRequestMinimum>
</security>
</trustInfo>
+
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of all Windows versions that this application is designed to work with.
Windows will automatically select the most compatible environment.-->
+
<!-- If your application is designed to work with Windows Vista, uncomment the following supportedOS node-->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>-->
+
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
+
<!-- If your application is designed to work with Windows 8, uncomment the following supportedOS node-->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>-->
+
</application>
</compatibility>
+
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<!-- <dependency>
<dependentAssembly>
@@ -49,4 +51,5 @@
/>
</dependentAssembly>
</dependency>-->
-</asmv1:assembly> \ No newline at end of file
+
+</asmv1:assembly>
diff --git a/windows/WinUI/packages.config b/windows/WinUI/packages.config
new file mode 100644
index 00000000..505e5883
--- /dev/null
+++ b/windows/WinUI/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/windows/ZeroTierOne.sln b/windows/ZeroTierOne.sln
index 1c6e58ed..68596187 100644
--- a/windows/ZeroTierOne.sln
+++ b/windows/ZeroTierOne.sln
@@ -1,13 +1,11 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver", "TapDriver\TapDriver.vcxproj", "{689210B1-467C-4850-BB7D-2E10D5B4A3DA}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroTierOne", "ZeroTierOne\ZeroTierOne.vcxproj", "{B00A4957-5977-4AC1-9EF4-571DC27EADA2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver6", "TapDriver6\TapDriver6.vcxproj", "{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebUIWrapper", "WebUIWrapper\WebUIWrapper.csproj", "{04832129-0F0C-438B-ACDF-8BB7F99AE241}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinUI", "WinUI\WinUI.csproj", "{4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -68,109 +66,6 @@ Global
Win8 Release|x86 = Win8 Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|Any CPU.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|Mixed Platforms.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|Mixed Platforms.Build.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|Mixed Platforms.Deploy.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|Win32.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|Win32.Build.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|Win32.Deploy.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|x64.ActiveCfg = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|x64.Build.0 = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|x64.Deploy.0 = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.CD_ROM|x86.ActiveCfg = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|Any CPU.ActiveCfg = Win8 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|Mixed Platforms.ActiveCfg = Win8 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|Win32.ActiveCfg = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|Win32.Build.0 = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|Win32.Deploy.0 = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|x64.ActiveCfg = Win7 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|x64.Build.0 = Win7 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|x64.Deploy.0 = Win7 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Debug|x86.ActiveCfg = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|Any CPU.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|Mixed Platforms.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|Mixed Platforms.Build.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|Mixed Platforms.Deploy.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|Win32.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|Win32.Build.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|Win32.Deploy.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|x64.ActiveCfg = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|x64.Build.0 = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|x64.Deploy.0 = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.DVD-5|x86.ActiveCfg = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|Any CPU.ActiveCfg = Win7 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|Mixed Platforms.ActiveCfg = Win7 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|Win32.ActiveCfg = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|Win32.Build.0 = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|Win32.Deploy.0 = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|x64.ActiveCfg = Win7 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|x64.Build.0 = Win7 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|x64.Deploy.0 = Win7 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Release|x86.ActiveCfg = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|Any CPU.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|Mixed Platforms.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|Mixed Platforms.Build.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|Mixed Platforms.Deploy.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|Win32.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|Win32.Build.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|Win32.Deploy.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|x64.ActiveCfg = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|x64.Build.0 = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|x64.Deploy.0 = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.SingleImage|x86.ActiveCfg = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|Any CPU.ActiveCfg = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|Mixed Platforms.ActiveCfg = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|Win32.ActiveCfg = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|Win32.Build.0 = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|Win32.Deploy.0 = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|x64.ActiveCfg = Vista Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|x64.Build.0 = Vista Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|x64.Deploy.0 = Vista Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Debug|x86.ActiveCfg = Vista Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|Any CPU.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|Mixed Platforms.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|Win32.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|Win32.Build.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|Win32.Deploy.0 = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|x64.ActiveCfg = Vista Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|x64.Build.0 = Vista Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|x64.Deploy.0 = Vista Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Vista Release|x86.ActiveCfg = Vista Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|Any CPU.ActiveCfg = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|Mixed Platforms.ActiveCfg = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|Win32.Deploy.0 = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|x64.ActiveCfg = Win7 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|x64.Build.0 = Win7 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|x64.Deploy.0 = Win7 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Debug|x86.ActiveCfg = Win7 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Release|Any CPU.ActiveCfg = Win7 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Release|Mixed Platforms.ActiveCfg = Win7 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Release|Win32.ActiveCfg = Win7 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Release|Win32.Build.0 = Win7 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Release|Win32.Deploy.0 = Win7 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Release|x64.ActiveCfg = Win7 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win7 Release|x86.ActiveCfg = Win7 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|Any CPU.ActiveCfg = Win8 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|Mixed Platforms.ActiveCfg = Win8 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|x64.Build.0 = Win8 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Debug|x86.ActiveCfg = Win8 Debug|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|Any CPU.ActiveCfg = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|Mixed Platforms.ActiveCfg = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|Win32.Build.0 = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|x64.ActiveCfg = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|x64.Build.0 = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|x64.Deploy.0 = Win8 Release|x64
- {689210B1-467C-4850-BB7D-2E10D5B4A3DA}.Win8 Release|x86.ActiveCfg = Win8 Release|Win32
{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.CD_ROM|Any CPU.ActiveCfg = Release|Win32
{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.CD_ROM|Mixed Platforms.ActiveCfg = Release|Win32
{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.CD_ROM|Mixed Platforms.Build.0 = Release|Win32
@@ -442,83 +337,83 @@ Global
{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.ActiveCfg = Win8 Release|Win32
{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.Build.0 = Win8 Release|Win32
{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.Deploy.0 = Win8 Release|Win32
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.CD_ROM|Mixed Platforms.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.CD_ROM|Mixed Platforms.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.CD_ROM|Win32.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.CD_ROM|x64.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.CD_ROM|x86.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Debug|x64.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Debug|x86.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.DVD-5|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.DVD-5|Mixed Platforms.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.DVD-5|Win32.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.DVD-5|x64.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.DVD-5|x86.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Release|Any CPU.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Release|Win32.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Release|x64.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Release|x86.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.SingleImage|Any CPU.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.SingleImage|Mixed Platforms.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.SingleImage|Mixed Platforms.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.SingleImage|Win32.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.SingleImage|x64.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.SingleImage|x86.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Debug|Any CPU.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Debug|Win32.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Debug|x64.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Debug|x86.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Release|Any CPU.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Release|Any CPU.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Release|Mixed Platforms.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Release|Win32.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Release|x64.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Vista Release|x86.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Debug|Any CPU.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Debug|Win32.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Debug|x64.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Debug|x86.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Release|Any CPU.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Release|Any CPU.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Release|Mixed Platforms.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Release|Win32.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Release|x64.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win7 Release|x86.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Debug|Any CPU.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Debug|Win32.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Debug|x64.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Debug|x86.ActiveCfg = Debug|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|Any CPU.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|Any CPU.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|Mixed Platforms.Build.0 = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|Win32.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|x64.ActiveCfg = Release|Any CPU
- {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|x86.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Mixed Platforms.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Win32.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|x64.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|x86.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Mixed Platforms.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Win32.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|x64.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|x86.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Win32.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|x64.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|x86.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Any CPU.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Mixed Platforms.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Win32.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|x64.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|x86.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Win32.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|x64.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|x86.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Any CPU.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Win32.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|x64.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|x86.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Win32.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|x64.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|x86.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Any CPU.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Win32.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|x64.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|x86.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Win32.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|x64.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|x86.ActiveCfg = Debug|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Any CPU.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Win32.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|x64.ActiveCfg = Release|Any CPU
+ {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj
index 0a43a6f6..5da01505 100644
--- a/windows/ZeroTierOne/ZeroTierOne.vcxproj
+++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj
@@ -22,9 +22,23 @@
<ClCompile Include="..\..\ext\http-parser\http_parser.c" />
<ClCompile Include="..\..\ext\json-parser\json.c" />
<ClCompile Include="..\..\ext\lz4\lz4.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\connecthostport.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\igd_desc_parse.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\minisoap.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\minissdpc.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\miniupnpc.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\miniwget.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\minixml.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\portlistingparse.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\receivedata.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\upnpcommands.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\upnpdev.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\upnperrors.c" />
+ <ClCompile Include="..\..\ext\miniupnpc\upnpreplyparse.c" />
<ClCompile Include="..\..\node\C25519.cpp" />
<ClCompile Include="..\..\node\CertificateOfMembership.cpp" />
- <ClCompile Include="..\..\node\Defaults.cpp" />
+ <ClCompile Include="..\..\node\Cluster.cpp" />
+ <ClCompile Include="..\..\node\DeferredPackets.cpp" />
<ClCompile Include="..\..\node\Dictionary.cpp" />
<ClCompile Include="..\..\node\Identity.cpp" />
<ClCompile Include="..\..\node\IncomingPacket.cpp" />
@@ -35,6 +49,7 @@
<ClCompile Include="..\..\node\Node.cpp" />
<ClCompile Include="..\..\node\OutboundMulticast.cpp" />
<ClCompile Include="..\..\node\Packet.cpp" />
+ <ClCompile Include="..\..\node\Path.cpp" />
<ClCompile Include="..\..\node\Peer.cpp" />
<ClCompile Include="..\..\node\Poly1305.cpp" />
<ClCompile Include="..\..\node\Salsa20.cpp" />
@@ -43,18 +58,14 @@
<ClCompile Include="..\..\node\Switch.cpp" />
<ClCompile Include="..\..\node\Topology.cpp" />
<ClCompile Include="..\..\node\Utils.cpp" />
- <ClCompile Include="..\..\one.cpp" />
+ <ClCompile Include="..\..\one.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
+ </ClCompile>
<ClCompile Include="..\..\osdep\BackgroundResolver.cpp" />
<ClCompile Include="..\..\osdep\Http.cpp" />
<ClCompile Include="..\..\osdep\OSUtils.cpp" />
<ClCompile Include="..\..\osdep\UPNPClient.cpp" />
<ClCompile Include="..\..\osdep\WindowsEthernetTap.cpp" />
- <ClCompile Include="..\..\selftest.cpp">
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
- </ClCompile>
<ClCompile Include="..\..\service\ControlPlane.cpp" />
<ClCompile Include="..\..\service\OneService.cpp" />
<ClCompile Include="ServiceBase.cpp" />
@@ -81,19 +92,38 @@
<ClInclude Include="..\..\ext\http-parser\http_parser.h" />
<ClInclude Include="..\..\ext\json-parser\json.h" />
<ClInclude Include="..\..\ext\lz4\lz4.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\codelength.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\connecthostport.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\igd_desc_parse.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\minisoap.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\minissdpc.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\miniupnpc.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\miniupnpctypes.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\miniupnpc_declspec.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\miniwget.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\minixml.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\portlistingparse.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\receivedata.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\upnpcommands.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\upnpdev.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\upnperrors.h" />
+ <ClInclude Include="..\..\ext\miniupnpc\upnpreplyparse.h" />
<ClInclude Include="..\..\include\ZeroTierOne.h" />
<ClInclude Include="..\..\node\Address.hpp" />
<ClInclude Include="..\..\node\AntiRecursion.hpp" />
<ClInclude Include="..\..\node\Array.hpp" />
<ClInclude Include="..\..\node\AtomicCounter.hpp" />
<ClInclude Include="..\..\node\BandwidthAccount.hpp" />
+ <ClInclude Include="..\..\node\BinarySemaphore.hpp" />
<ClInclude Include="..\..\node\Buffer.hpp" />
<ClInclude Include="..\..\node\C25519.hpp" />
<ClInclude Include="..\..\node\CertificateOfMembership.hpp" />
+ <ClInclude Include="..\..\node\Cluster.hpp" />
<ClInclude Include="..\..\node\CMWC4096.hpp" />
<ClInclude Include="..\..\node\Constants.hpp" />
- <ClInclude Include="..\..\node\Defaults.hpp" />
+ <ClInclude Include="..\..\node\DeferredPackets.hpp" />
<ClInclude Include="..\..\node\Dictionary.hpp" />
+ <ClInclude Include="..\..\node\Hashtable.hpp" />
<ClInclude Include="..\..\node\Identity.hpp" />
<ClInclude Include="..\..\node\IncomingPacket.hpp" />
<ClInclude Include="..\..\node\InetAddress.hpp" />
@@ -111,7 +141,6 @@
<ClInclude Include="..\..\node\Path.hpp" />
<ClInclude Include="..\..\node\Peer.hpp" />
<ClInclude Include="..\..\node\Poly1305.hpp" />
- <ClInclude Include="..\..\node\RemotePath.hpp" />
<ClInclude Include="..\..\node\RuntimeEnvironment.hpp" />
<ClInclude Include="..\..\node\Salsa20.hpp" />
<ClInclude Include="..\..\node\SelfAwareness.hpp" />
@@ -120,6 +149,7 @@
<ClInclude Include="..\..\node\Switch.hpp" />
<ClInclude Include="..\..\node\Topology.hpp" />
<ClInclude Include="..\..\node\Utils.hpp" />
+ <ClInclude Include="..\..\node\World.hpp" />
<ClInclude Include="..\..\osdep\BackgroundResolver.hpp" />
<ClInclude Include="..\..\osdep\Http.hpp" />
<ClInclude Include="..\..\osdep\OSUtils.hpp" />
@@ -213,11 +243,11 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
@@ -228,11 +258,12 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MultiProcessorCompilation>false</MultiProcessorCompilation>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
@@ -245,7 +276,7 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<StringPooling>true</StringPooling>
@@ -257,7 +288,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
- <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
@@ -270,7 +301,7 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
<StringPooling>true</StringPooling>
@@ -282,7 +313,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
- <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters
index abaa8547..6475137c 100644
--- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters
+++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters
@@ -79,6 +79,12 @@
<Filter Include="Header Files\ext\bin\miniupnpc\include">
<UniqueIdentifier>{1a47071e-e51b-4535-89ae-858946f03118}</UniqueIdentifier>
</Filter>
+ <Filter Include="Header Files\ext\miniupnpc">
+ <UniqueIdentifier>{5423fb64-896b-432e-a19d-88d4467f89f9}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\ext\miniupnpc">
+ <UniqueIdentifier>{56cc3ab8-3336-4a22-9471-c267ee46cd54}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\service\ControlPlane.cpp">
@@ -96,18 +102,12 @@
<ClCompile Include="..\..\osdep\OSUtils.cpp">
<Filter>Source Files\osdep</Filter>
</ClCompile>
- <ClCompile Include="..\..\selftest.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="..\..\node\C25519.cpp">
<Filter>Source Files\node</Filter>
</ClCompile>
<ClCompile Include="..\..\node\CertificateOfMembership.cpp">
<Filter>Source Files\node</Filter>
</ClCompile>
- <ClCompile Include="..\..\node\Defaults.cpp">
- <Filter>Source Files\node</Filter>
- </ClCompile>
<ClCompile Include="..\..\node\Dictionary.cpp">
<Filter>Source Files\node</Filter>
</ClCompile>
@@ -189,6 +189,54 @@
<ClCompile Include="..\..\osdep\UPNPClient.cpp">
<Filter>Source Files\osdep</Filter>
</ClCompile>
+ <ClCompile Include="..\..\node\Path.cpp">
+ <Filter>Source Files\node</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\node\DeferredPackets.cpp">
+ <Filter>Source Files\node</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\node\Cluster.cpp">
+ <Filter>Source Files\node</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\connecthostport.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\igd_desc_parse.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\minisoap.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\minissdpc.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\miniupnpc.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\miniwget.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\minixml.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\portlistingparse.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\receivedata.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\upnpcommands.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\upnpdev.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\upnperrors.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\ext\miniupnpc\upnpreplyparse.c">
+ <Filter>Source Files\ext\miniupnpc</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
@@ -254,9 +302,6 @@
<ClInclude Include="..\..\node\Constants.hpp">
<Filter>Header Files\node</Filter>
</ClInclude>
- <ClInclude Include="..\..\node\Defaults.hpp">
- <Filter>Header Files\node</Filter>
- </ClInclude>
<ClInclude Include="..\..\node\Dictionary.hpp">
<Filter>Header Files\node</Filter>
</ClInclude>
@@ -356,9 +401,6 @@
<ClInclude Include="..\..\osdep\BackgroundResolver.hpp">
<Filter>Header Files\osdep</Filter>
</ClInclude>
- <ClInclude Include="..\..\node\RemotePath.hpp">
- <Filter>Header Files\node</Filter>
- </ClInclude>
<ClInclude Include="..\..\osdep\UPNPClient.hpp">
<Filter>Header Files\osdep</Filter>
</ClInclude>
@@ -410,6 +452,69 @@
<ClInclude Include="..\..\ext\bin\miniupnpc\include\miniupnpc\upnpreplyparse.h">
<Filter>Header Files\ext\bin\miniupnpc\include</Filter>
</ClInclude>
+ <ClInclude Include="..\..\node\BinarySemaphore.hpp">
+ <Filter>Header Files\node</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\node\Cluster.hpp">
+ <Filter>Header Files\node</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\node\Hashtable.hpp">
+ <Filter>Header Files\node</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\node\DeferredPackets.hpp">
+ <Filter>Header Files\node</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\node\World.hpp">
+ <Filter>Header Files\node</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\codelength.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\connecthostport.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\igd_desc_parse.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\minisoap.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\minissdpc.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\miniupnpc.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\miniupnpc_declspec.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\miniupnpctypes.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\miniwget.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\minixml.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\portlistingparse.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\receivedata.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\upnpcommands.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\upnpdev.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\upnperrors.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\ext\miniupnpc\upnpreplyparse.h">
+ <Filter>Header Files\ext\miniupnpc</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ZeroTierOne.rc">
diff --git a/windows/packages/.gitignore b/windows/packages/.gitignore
new file mode 100644
index 00000000..0acda714
--- /dev/null
+++ b/windows/packages/.gitignore
@@ -0,0 +1,3 @@
+*
+!repositories.config
+!.gitignore \ No newline at end of file
diff --git a/windows/packages/repositories.config b/windows/packages/repositories.config
new file mode 100644
index 00000000..f8197655
--- /dev/null
+++ b/windows/packages/repositories.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<repositories>
+ <repository path="..\WinUI\packages.config" />
+</repositories> \ No newline at end of file
diff --git a/world/README.md b/world/README.md
new file mode 100644
index 00000000..dda4920a
--- /dev/null
+++ b/world/README.md
@@ -0,0 +1,7 @@
+World Definitions and Generator Code
+======
+
+This little bit of code is used to generate world updates. Ordinary users probably will never need this unless they want to test or experiment.
+
+See mkworld.cpp for documentation. To build from this directory use 'source ./build.sh'.
+
diff --git a/world/build.sh b/world/build.sh
new file mode 100755
index 00000000..b783702c
--- /dev/null
+++ b/world/build.sh
@@ -0,0 +1 @@
+c++ -I.. -o mkworld ../node/C25519.cpp ../node/Salsa20.cpp ../node/SHA512.cpp ../node/Identity.cpp ../node/Utils.cpp ../node/InetAddress.cpp ../osdep/OSUtils.cpp mkworld.cpp
diff --git a/world/earth-2015-11-16.bin b/world/earth-2015-11-16.bin
new file mode 100644
index 00000000..910ff144
--- /dev/null
+++ b/world/earth-2015-11-16.bin
Binary files differ
diff --git a/world/earth-2015-11-20.bin b/world/earth-2015-11-20.bin
new file mode 100644
index 00000000..198682e5
--- /dev/null
+++ b/world/earth-2015-11-20.bin
Binary files differ
diff --git a/world/mkworld.cpp b/world/mkworld.cpp
new file mode 100644
index 00000000..a14aa55c
--- /dev/null
+++ b/world/mkworld.cpp
@@ -0,0 +1,187 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015 ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+/*
+ * This utility makes the World from the configuration specified below.
+ * It probably won't be much use to anyone outside ZeroTier, Inc. except
+ * for testing and experimentation purposes.
+ *
+ * If you want to make your own World you must edit this file.
+ *
+ * When run, it expects two files in the current directory:
+ *
+ * previous.c25519 - key pair to sign this world (key from previous world)
+ * current.c25519 - key pair whose public key should be embedded in this world
+ *
+ * If these files do not exist, they are both created with the same key pair
+ * and a self-signed initial World is born.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include <node/Constants.hpp>
+#include <node/World.hpp>
+#include <node/C25519.hpp>
+#include <node/Identity.hpp>
+#include <node/InetAddress.hpp>
+#include <osdep/OSUtils.hpp>
+
+using namespace ZeroTier;
+
+class WorldMaker : public World
+{
+public:
+ static inline World make(uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector<World::Root> &roots,const C25519::Pair &signWith)
+ {
+ WorldMaker w;
+ w._id = id;
+ w._ts = ts;
+ w._updateSigningKey = sk;
+ w._roots = roots;
+
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
+ w.serialize(tmp,true);
+ w._signature = C25519::sign(signWith,tmp.data(),tmp.size());
+
+ return w;
+ }
+};
+
+int main(int argc,char **argv)
+{
+ std::string previous,current;
+ if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) {
+ C25519::Pair np(C25519::generate());
+ previous = std::string();
+ previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
+ previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
+ current = previous;
+ OSUtils::writeFile("previous.c25519",previous);
+ OSUtils::writeFile("current.c25519",current);
+ fprintf(stderr,"INFO: created initial world keys: previous.c25519 and current.c25519 (both initially the same)"ZT_EOL_S);
+ }
+
+ if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) {
+ fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid"ZT_EOL_S);
+ return 1;
+ }
+ C25519::Pair previousKP;
+ memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN);
+ memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN);
+ C25519::Pair currentKP;
+ memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN);
+ memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN);
+
+ // =========================================================================
+ // EDIT BELOW HERE
+
+ std::vector<World::Root> roots;
+
+ const uint64_t id = ZT_WORLD_ID_EARTH;
+ const uint64_t ts = 1448048819338ULL; // November 20th, 2015 ~11:47AM
+
+ // Alice
+ roots.push_back(World::Root());
+ roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e");
+ roots.back().stableEndpoints.push_back(InetAddress("188.166.94.177/9993")); // Amsterdam
+ roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:2:d0::7d:1/9993")); // Amsterdam
+ roots.back().stableEndpoints.push_back(InetAddress("154.66.197.33/9993")); // Johannesburg
+ roots.back().stableEndpoints.push_back(InetAddress("2c0f:f850:154:197::33/9993")); // Johannesburg
+ roots.back().stableEndpoints.push_back(InetAddress("159.203.97.171/9993")); // New York
+ roots.back().stableEndpoints.push_back(InetAddress("2604:a880:800:a1::54:6001/9993")); // New York
+ roots.back().stableEndpoints.push_back(InetAddress("169.57.143.104/9993")); // Sao Paolo
+ roots.back().stableEndpoints.push_back(InetAddress("2607:f0d0:1d01:57::2/9993")); // Sao Paolo
+ roots.back().stableEndpoints.push_back(InetAddress("107.170.197.14/9993")); // San Francisco
+ roots.back().stableEndpoints.push_back(InetAddress("2604:a880:1:20::200:e001/9993")); // San Francisco
+ roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); // Singapore
+ roots.back().stableEndpoints.push_back(InetAddress("2400:6180:0:d0::b7:4001/9993")); // Singapore
+
+ // Bob
+ roots.push_back(World::Root());
+ roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c");
+ roots.back().stableEndpoints.push_back(InetAddress("45.32.198.130/9993")); // Dallas
+ roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6400:81c3:5400:00ff:fe18:1d61/9993")); // Dallas
+ roots.back().stableEndpoints.push_back(InetAddress("46.101.160.249/9993")); // Frankfurt
+ roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:3:d0::6a:3001/9993")); // Frankfurt
+ roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); // Paris
+ roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6800:83a4::64/9993")); // Paris
+ roots.back().stableEndpoints.push_back(InetAddress("45.32.246.179/9993")); // Sydney
+ roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:5800:8bf8:5400:ff:fe15:b39a/9993")); // Sydney
+ roots.back().stableEndpoints.push_back(InetAddress("45.32.248.87/9993")); // Tokyo
+ roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:7000:9bc9:5400:00ff:fe15:c4f5/9993")); // Tokyo
+ roots.back().stableEndpoints.push_back(InetAddress("159.203.2.154/9993")); // Toronto
+ roots.back().stableEndpoints.push_back(InetAddress("2604:a880:cad:d0::26:7001/9993")); // Toronto
+
+ // old US-SFO -- we will keep these around for a little while
+ roots.push_back(World::Root());
+ roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa");
+ roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993"));
+
+ // old US-NYC -- we will keep these around for a little while
+ roots.push_back(World::Root());
+ roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5");
+ roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993"));
+
+ // END WORLD DEFINITION
+ // =========================================================================
+
+ fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu"ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts);
+
+ World nw = WorldMaker::make(id,ts,currentKP.pub,roots,previousKP);
+
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> outtmp;
+ nw.serialize(outtmp,false);
+ World testw;
+ testw.deserialize(outtmp,0);
+ if (testw != nw) {
+ fprintf(stderr,"FATAL: serialization test failed!"ZT_EOL_S);
+ return 1;
+ }
+
+ OSUtils::writeFile("world.bin",std::string((const char *)outtmp.data(),outtmp.size()));
+ fprintf(stderr,"INFO: world.bin written with %u bytes of binary world data."ZT_EOL_S,outtmp.size());
+
+ fprintf(stdout,ZT_EOL_S);
+ fprintf(stdout,"#define ZT_DEFAULT_WORLD_LENGTH %u"ZT_EOL_S,outtmp.size());
+ fprintf(stdout,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {");
+ for(unsigned int i=0;i<outtmp.size();++i) {
+ const unsigned char *d = (const unsigned char *)outtmp.data();
+ if (i > 0)
+ fprintf(stdout,",");
+ fprintf(stdout,"0x%.2x",(unsigned int)d[i]);
+ }
+ fprintf(stdout,"};"ZT_EOL_S);
+
+ return 0;
+}